Initialize_Entities: LD A, $mem_bunny_mana LD E, A LD A, $mem_bunny_health LD D, A LD HL, $mem_entities_list Clear_Entities.loop: XOR A LD (HL+), A CP L JR NZ, =Clear_Entities.loop LD A, D LD $mem_bunny_health, A LD A, E LD $mem_bunny_mana, A CALL =Initialize_Bunny_Random_room LD A, $00 LD $mem_enemies_alive_count, A LD A, $mem_bunny_current_room_idx LD $tmp_var_1, A LD A, $ff LD $mem_bunny_current_room_idx, A LD A, $mem_dungeon_flags BIT 2, A JP Z, =Reset_Entities_Collision_Map LD A, $00 LD $tmp_var_3, A CALL =Initialize_Enemy CALL =Initialize_Enemy CALL =Initialize_Enemy CALL =Initialize_Enemy CALL =Initialize_Enemy LD A, $tmp_var_1 LD $mem_bunny_current_room_idx, A JP =Reset_Entities_Collision_Map Initialize_Bunny_Random_room: LD A, $ff CALL =Pick_Random_Room_Avoid_A LD $mem_bunny_current_room_idx, A CALL =Pick_Room_position Initialize_Bunny: ; BC is XY position LD HL, $mem_entities_list LD A, $01 LD (HL+), A LD (HL), B INC HL LD (HL), C CALL =Carve_Entity_Collision_Map INC HL LD A, $enum_direction_down LD (HL), A SWAP A OR (HL) LD (HL+), A ; Turn LD A, $01 LD (HL+), A ; Action LD A, $00 LD (HL+), A INC HL ; skip health LD A, $00 ; Flags LD (HL+), A ; Status LD (HL+), A LD A, L AND $f0 ADD $10 LD L, A RET Initialize_Enemy: ; HL => pointer to entity struct CALL =Enemy_idx_to_spawn CP $ff RET Z ADD $03 Initialize_Entity: ; HL => pointer to entity struct, A => entity loaded index, 1 in $tmp_var_3 if should retry if collsion (could potentially fail multiple time/infinite loop) LD E, A SLA A SLA A LD B, A SLA A ADD B INC A LD (HL), A LD A, $mem_bunny_current_room_idx CALL =Pick_Room_position_Avoid_A ; Check if spawning on collisionable tile CALL =Is_Collisionable CP $00 JR Z, =.no_collision XOR A LD (HL), A LD A, $tmp_var_3 CP $01 RET NZ LD A, E JP =Initialize_Entity .no_collision: INC HL LD (HL), B INC HL LD (HL), C INC HL CALL =Carve_Entity_Collision_Map POP BC ; Direction LD A, $33 LD (HL+), A LD A, E CALL =Entity_idx_to_entity_list_ptr INC BC INC BC ; Turn LD A, (BC) LD (HL+), A INC BC ; Action LD A, (BC) LD (HL+), A INC BC ; Health LD A, (BC) LD (HL+), A INC BC XOR A ; flags & status LD (HL+), A LD A, (BC) LD (HL+), A INC BC ; Mana LD A, (BC) LD (HL+), A LD A, L ADD $06 LD L, A LD A, E CP $03 RET C CP $07 RET NC LD A, $mem_enemies_alive_count INC A LD $mem_enemies_alive_count, A RET FindFreeEntity: LD HL, $mem_entities_list FindFreeEntity.loop: ; This loop supposes that there is indeed enough space for a new entity ; to be spawn (thus the previous mem_enemies_alive_count). ; If entities are changed at some point to contain things that are not ; counted in mem_enemies_alive_count, this could result in an infinite loop. ; (Technically the quest goals can spawn other entities. We assume that the enemies alive count and the quest goal entities spawned will never exceed 15 together) LD A, L AND $f0 ADD $10 LD L, A LD A, $00 CP (HL) JR NZ, =FindFreeEntity.loop RET Respawn_Entities: LD A, $mem_dungeon_flags BIT 2, A RET Z LD A, $mem_moving_animation_step CP $04 RET NZ LD A, $mem_enemies_alive_count CP $05 RET NC LD A, $00 LD $tmp_var_3, A CALL =RNG_Step AND $07 CP $00 RET NZ CALL =FindFreeEntity CALL =Initialize_Enemy RET Enemy_spawn_pattern_to_probability: ; (1/(x + 1)) .DB 0b11111111 .DB 0b00000111 .DB 0b00000001 .DB 0b00000000 Enemy_idx_to_spawn: ; Return in A, ff if no entity to be spawned PUSH BC LD A, $mem_entity_spawning_pattern LD B, A CALL =RNG_Step AND $03 LD C, A SLA A CALL =RRx LD A, B AND $03 PUSH DE LD DE, =Enemy_spawn_pattern_to_probability ADD E LD E, A LD A, D ADC $00 LD D, A LD A, (DE) POP DE LD B, A CALL =RNG_Step AND B CP $00 LD A, $ff JR NZ, =.skip_set_enemy_idx LD A, C .skip_set_enemy_idx: POP BC RET .MACRODEF GET_ENTITY_IDX_SPAWN_RATE idx ; breaks BC & A LD A, low($idx) CALL =Entity_idx_to_entity_list_ptr LD A, C ADD $07 LD C, A LD A, B ADC $00 LD B, A LD A, (BC) AND $03 .END