Render All Ships Patch
Summary
This patch modifies P3 to render all ships on the scrollmap, not just the up to two ships spotted by each player ship or convoy.
Details
The first half of the draw_spotted_ships
function at 004516B0
determines which ships should be rendered.
It produces three things of interest:
- the amount of ships that should be drawn
- an array of ship indexes that should be drawn
- an array of ship y coordinates
The rest of the function does not have to be modified.
Patch
The following function fixup_all_ships
takes pointers to the two arrays as an argument, and returns the amount of ships that should be drawn.
It only enqueues ships whose status is 0xf
(merchant vessel at sea) and 0x12
(AI pirate vessel).
#include <stdint.h>
#define CLASS6_PTR 0x006DD7A0
inline void* get_ship_by_index(uint16_t index) {
uint32_t ships_ptr = *(uint32_t*) (CLASS6_PTR + 0x04);
return (void*) ships_ptr + 0x180 * (uint32_t) index;
}
inline uint16_t get_ships_size() {
return *(uint16_t*) (CLASS6_PTR + 0xf4);
}
inline uint16_t get_ship_status(void* ship) {
return *(uint16_t*) (((uint32_t) ship) + 0x134);
}
inline uint16_t get_ship_y_high(void* ship) {
return *(uint16_t*) (((uint32_t) ship) + 0x22);
}
uint32_t fixup_all_ships(uint32_t* spotted_y, uint32_t* spotted_index) {
uint16_t ships_size = get_ships_size();
int new_spotted_size = 0;
for (uint16_t i = 0; i < ships_size; i++) {
void* ship = get_ship_by_index(i);
uint16_t status = get_ship_status(ship);
if (status != 0x12 && status != 0xf) {
continue;
}
spotted_y[new_spotted_size] = get_ship_y_high(ship);
spotted_index[new_spotted_size] = i;
new_spotted_size += 1;
}
return new_spotted_size;
}
Built with gcc 14.1 (-m32 -O3 -fno-stack-protector
) this generates the following assembly:
fixup_all_ships:
push ebp
push edi
push esi
push ebx
movzx ebx, WORD PTR ds:7198868
mov esi, DWORD PTR [esp+20]
mov edi, DWORD PTR [esp+24]
test bx, bx
je .L6
xor ecx, ecx
xor eax, eax
.L5:
lea edx, [ecx+ecx*2]
sal edx, 7
add edx, DWORD PTR ds:7198628
movzx ebp, WORD PTR [edx+308]
cmp bp, 18
je .L7
cmp bp, 15
jne .L3
.L7:
movzx edx, WORD PTR [edx+34]
mov DWORD PTR [esi+eax*4], edx
mov DWORD PTR [edi+eax*4], ecx
add eax, 1
.L3:
add ecx, 1
cmp ebx, ecx
jne .L5
pop ebx
pop esi
pop edi
pop ebp
ret
.L6:
pop ebx
xor eax, eax
pop esi
pop edi
pop ebp
ret
A jump to fixup_all_ships
has to be injected at 0x00451759
with the following assembly instructions.
#ADDRESSOFPATCH needs to be replaced with the address of fixup_all_ships
.
# save regs
push eax
push ecx
push edx
# call fixup_all_ships
mov eax, [esp+0x30]
mov ecx, [esp+0x2C]
push ecx
push eax
mov edx, #ADDRESSOFPATCH
call edx
mov ebp, eax
pop eax
pop eax
# restore regs
pop edx
pop ecx
pop eax
# jump to second part of draw_spotted_ships
mov eax, 0x00451B58
jmp eax