; hunter — chases the nearest enemy in view, attacks when adjacent, splits when ; strong, and otherwise wanders in a remembered direction so the colony spreads. ; ; Memory layout ([rdx]): ; byte 0 wander direction (0..3) lea r8, [rdi + VIEW_CELLS] ; ---- adjacent enemy? attack it ------------------------------------- cmp byte [r8 + 7], CELL_ENEMY je .atk_up cmp byte [r8 + 13], CELL_ENEMY je .atk_right cmp byte [r8 + 17], CELL_ENEMY je .atk_down cmp byte [r8 + 11], CELL_ENEMY je .atk_left ; ---- scan the 5x5 for the nearest enemy (manhattan distance) -------- mov r9d, 99 ; best distance so far mov r10d, -1 ; best index so far xor ecx, ecx ; index 0..24 .scan: cmp byte [r8 + rcx], CELL_ENEMY jne .next mov eax, ecx xor edx, edx mov r11d, 5 div r11d ; eax = dy+2, edx = dx+2 sub eax, 2 sub edx, 2 mov r11d, eax sar r11d, 31 xor eax, r11d sub eax, r11d ; |dy| mov r11d, edx sar r11d, 31 xor edx, r11d sub edx, r11d ; |dx| add eax, edx cmp eax, r9d jae .next mov r9d, eax mov r10d, ecx .next: inc ecx cmp ecx, 25 jb .scan mov rdx, CELLMEM_BASE ; div clobbered rdx; restore the memory pointer cmp r10d, -1 je .no_enemy ; ---- move toward the enemy at index r10 ----------------------------- cmp rsi, MOVE_COST + 6 jb .rest ; too weak to chase; rest instead mov eax, r10d xor edx, edx mov ecx, 5 div ecx sub eax, 2 ; dy sub edx, 2 ; dx mov r9d, eax ; r9d = dy mov r11d, edx ; r11d = dx cdq xor eax, edx sub eax, edx ; |dy| mov ebx, eax mov eax, r11d cdq xor eax, edx sub eax, edx ; |dx| mov rdx, CELLMEM_BASE cmp eax, ebx jae .x_first call .step_y test al, al jnz .go call .step_x test al, al jnz .go jmp .rest .x_first: call .step_x test al, al jnz .go call .step_y test al, al jnz .go jmp .rest ; .step_y / .step_x: cl = direction toward the target along that axis, ; al = 1 if the neighbouring square in that direction is empty. .step_y: mov cl, DIR_DOWN mov r10d, 17 test r9d, r9d jns .sy mov cl, DIR_UP mov r10d, 7 .sy: xor eax, eax cmp byte [r8 + r10], CELL_EMPTY sete al ret .step_x: mov cl, DIR_RIGHT mov r10d, 13 test r11d, r11d jns .sx mov cl, DIR_LEFT mov r10d, 11 .sx: xor eax, eax cmp byte [r8 + r10], CELL_EMPTY sete al ret .go: mov al, ACT_MOVE or al, cl ret ; ---- nothing in sight: grow or wander -------------------------------- .no_enemy: cmp rsi, SPLIT_MIN + 12 jb .wander movzx ecx, byte [rdx] ; prefer splitting in the wander direction mov r9d, 4 .split_try: and ecx, 3 lea r11, [neighbour_idx] movzx r10d, byte [r11 + rcx] cmp byte [r8 + r10], CELL_EMPTY je .split inc ecx dec r9d jnz .split_try jmp .rest .split: mov al, ACT_SPLIT or al, cl ret .wander: cmp rsi, 60 jb .rest ; too poor to walk; rest up first movzx ecx, byte [rdx] and ecx, 3 lea r11, [neighbour_idx] movzx r10d, byte [r11 + rcx] cmp byte [r8 + r10], CELL_EMPTY je .walk movzx eax, byte [rdi + VIEW_RAND] ; blocked: pick a new direction, rest this tick and al, 3 mov [rdx], al jmp .rest .walk: mov al, ACT_MOVE or al, cl ret .rest: mov al, ACT_REST ret .atk_up: mov al, ACT_ATTACK + DIR_UP ret .atk_right: mov al, ACT_ATTACK + DIR_RIGHT ret .atk_down: mov al, ACT_ATTACK + DIR_DOWN ret .atk_left: mov al, ACT_ATTACK + DIR_LEFT ret neighbour_idx: db 7, 13, 17, 11 ; VIEW_CELLS index of the square in each direction