fp: Add mobbing behaviour to surround club terry
This commit is contained in:
		
							parent
							
								
									378ef2959b
								
							
						
					
					
						commit
						158fcb12fe
					
				
							
								
								
									
										108
									
								
								feely_pona.cpp
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								feely_pona.cpp
									
									
									
									
									
								
							| @ -4,38 +4,6 @@ | ||||
| #endif | ||||
| 
 | ||||
| Dqn_f32 const PHYSICS_STEP = 1 / 60.f; | ||||
| struct FP_GlobalAnimations | ||||
| { | ||||
|     Dqn_String8 terry_walk_idle       = DQN_STRING8("terry_walk_idle"); | ||||
|     Dqn_String8 terry_walk_up         = DQN_STRING8("terry_walk_up"); | ||||
|     Dqn_String8 terry_walk_down       = DQN_STRING8("terry_walk_down"); | ||||
|     Dqn_String8 terry_walk_left       = DQN_STRING8("terry_walk_left"); | ||||
|     Dqn_String8 terry_walk_right      = DQN_STRING8("terry_walk_right"); | ||||
|     Dqn_String8 terry_attack_up       = DQN_STRING8("terry_attack_up"); | ||||
|     Dqn_String8 terry_attack_side     = DQN_STRING8("terry_attack_side"); | ||||
|     Dqn_String8 terry_attack_down     = DQN_STRING8("terry_attack_down"); | ||||
|     Dqn_String8 terry_merchant        = DQN_STRING8("terry_merchant"); | ||||
| 
 | ||||
|     Dqn_String8 smoochie_walk_up      = DQN_STRING8("smoochie_walk_up"); | ||||
|     Dqn_String8 smoochie_walk_down    = DQN_STRING8("smoochie_walk_down"); | ||||
|     Dqn_String8 smoochie_walk_left    = DQN_STRING8("smoochie_walk_left"); | ||||
|     Dqn_String8 smoochie_walk_right   = DQN_STRING8("smoochie_walk_right"); | ||||
|     Dqn_String8 smoochie_attack_down  = DQN_STRING8("smoochie_attack_down"); | ||||
|     Dqn_String8 smoochie_hurt_side    = DQN_STRING8("smoochie_hurt_side"); | ||||
|     Dqn_String8 smoochie_attack_heart = DQN_STRING8("smoochie_attack_heart"); | ||||
|     Dqn_String8 smoochie_death        = DQN_STRING8("smoochie_death"); | ||||
| 
 | ||||
|     Dqn_String8 clinger_attack_down = DQN_STRING8("clinger_attack_down"); | ||||
|     Dqn_String8 clinger_attack_side = DQN_STRING8("clinger_attack_side"); | ||||
|     Dqn_String8 clinger_attack_up   = DQN_STRING8("clinger_attack_up"); | ||||
|     Dqn_String8 clinger_death       = DQN_STRING8("clinger_death"); | ||||
|     Dqn_String8 clinger_walk_up     = DQN_STRING8("clinger_walk_up"); | ||||
|     Dqn_String8 clinger_walk_down   = DQN_STRING8("clinger_walk_down"); | ||||
| 
 | ||||
|     Dqn_String8 club_terry_alive  = DQN_STRING8("club_terry_alive"); | ||||
|     Dqn_String8 club_terry_dark   = DQN_STRING8("club_terry_dark"); | ||||
| } | ||||
| g_anim_names; | ||||
| 
 | ||||
| TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_Assets *assets, Dqn_Arena *arena, Dqn_String8 sheet_name) | ||||
| { | ||||
| @ -964,8 +932,10 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input | ||||
|                         move_entity = *state == FP_EntityClingerState_Run || *state == FP_EntityClingerState_Idle; | ||||
|                     } break; | ||||
| 
 | ||||
|                     case FP_EntityType_Merchant: break; | ||||
|                     case FP_EntityType_Nil:      break; | ||||
|                     case FP_EntityType_Merchant:  break; | ||||
|                     case FP_EntityType_Nil:       break; | ||||
|                     case FP_EntityType_ClubTerry: break; | ||||
|                     case FP_EntityType_Count:     break; | ||||
|                 } | ||||
| 
 | ||||
|                 if (move_entity) { | ||||
| @ -988,30 +958,14 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input | ||||
|             Dqn_V2 entity_pos = FP_Game_CalcEntityWorldPos(game, entity->handle); | ||||
| 
 | ||||
|             if (entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) { | ||||
|                 Dqn_f32 closest_terry_dist   = DQN_F32_MAX; | ||||
|                 Dqn_V2 closest_terry_pos     = Dqn_V2_InitNx1(DQN_F32_MAX); | ||||
|                 FP_GameEntity *closest_terry = nullptr; | ||||
|                 for (FP_GameEntityIterator terry_it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &terry_it, game->root_entity); ) { | ||||
|                     FP_GameEntity *terry = terry_it.entity; | ||||
|                     if (terry->type != FP_EntityType_Terry) | ||||
|                         continue; | ||||
| 
 | ||||
|                     Dqn_V2 terry_pos      = FP_Game_CalcEntityWorldPos(game, terry->handle); | ||||
|                     Dqn_f32 dist_to_terry = Dqn_V2_LengthSq_V2x2(terry_pos, entity_pos); | ||||
|                     if (dist_to_terry < closest_terry_dist) { | ||||
|                         closest_terry_pos  = terry_pos; | ||||
|                         closest_terry_dist = dist_to_terry; | ||||
|                         closest_terry      = terry; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (closest_terry_dist < DQN_SQUARED(FP_Game_MetersToPixelsNx1(game, 4.f))) { | ||||
|                 FP_GameFindClosestEntityResult closest_result = FP_Game_FindClosestEntityWithType(game, entity->handle, FP_EntityType_Terry); | ||||
|                 if (closest_result.dist_squared < DQN_SQUARED(FP_Game_MetersToPixelsNx1(game, 4.f))) { | ||||
|                     FP_SentinelListLink<FP_GameWaypoint> *first_waypoint = FP_SentinelList_Front(&entity->waypoints); | ||||
|                     if (first_waypoint->data.entity != closest_terry->handle) { | ||||
| 
 | ||||
|                     if (first_waypoint->data.entity != closest_result.entity) { | ||||
|                         FP_GameEntity *terry             = FP_Game_GetEntity(game, closest_result.entity); | ||||
|                         FP_GameDirection aggro_direction = FP_GameDirection_Count; | ||||
|                         DQN_FOR_UINDEX(dir_index, FP_GameDirection_Count) { | ||||
|                             FP_GameEntityHandle slot_entity_handle = closest_terry->aggro_slot[dir_index]; | ||||
|                             FP_GameEntityHandle slot_entity_handle = terry->aggro_slot[dir_index]; | ||||
|                             FP_GameEntity *slot_entity             = FP_Game_GetEntity(game, slot_entity_handle); | ||||
|                             if (FP_Game_IsNilEntity(slot_entity)) { | ||||
|                                 aggro_direction = DQN_CAST(FP_GameDirection)dir_index; | ||||
| @ -1021,17 +975,33 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input | ||||
| 
 | ||||
|                         FP_SentinelListLink<FP_GameWaypoint> *link = FP_SentinelList_MakeBefore(&entity->waypoints, first_waypoint, game->chunk_pool); | ||||
|                         FP_GameWaypoint *waypoint                  = &link->data; | ||||
|                         waypoint->entity                           = closest_terry->handle; | ||||
|                         waypoint->entity                           = terry->handle; | ||||
| 
 | ||||
|                         if (aggro_direction != FP_GameDirection_Count) { | ||||
|                             waypoint->type                             = FP_GameWaypointType_Side; | ||||
|                             waypoint->type_direction                   = aggro_direction; | ||||
|                             closest_terry->aggro_slot[aggro_direction] = entity->handle; | ||||
|                             waypoint->type                     = FP_GameWaypointType_Side; | ||||
|                             waypoint->type_direction           = aggro_direction; | ||||
|                             terry->aggro_slot[aggro_direction] = entity->handle; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (entity->flags & FP_GameEntityFlag_RespondsToClubTerry) { | ||||
|                 FP_GameFindClosestEntityResult closest_result = FP_Game_FindClosestEntityWithType(game, entity->handle, FP_EntityType_ClubTerry); | ||||
|                 if (closest_result.dist_squared < DQN_SQUARED(FP_Game_MetersToPixelsNx1(game, 4.f))) { | ||||
|                     FP_SentinelListLink<FP_GameWaypoint> *first_waypoint = FP_SentinelList_Front(&entity->waypoints); | ||||
|                     if (first_waypoint->data.entity != closest_result.entity) { | ||||
|                         FP_GameEntity *club_terry = FP_Game_GetEntity(game, closest_result.entity); | ||||
| 
 | ||||
|                         FP_SentinelListLink<FP_GameWaypoint> *link = FP_SentinelList_MakeBefore(&entity->waypoints, first_waypoint, game->chunk_pool); | ||||
|                         FP_GameWaypoint *waypoint = &link->data; | ||||
|                         waypoint->entity          = club_terry->handle; | ||||
|                         waypoint->type            = FP_GameWaypointType_Side; | ||||
|                         waypoint->type_direction  = FP_GameDirection_Down; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             while (entity->waypoints.size) { | ||||
|                 FP_SentinelListLink<FP_GameWaypoint> *waypoint_link = entity->waypoints.sentinel->next; | ||||
|                 FP_GameWaypoint const *waypoint                     = &waypoint_link->data; | ||||
| @ -1051,7 +1021,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input | ||||
|                 Dqn_f32 arrival_threshold = {}; | ||||
|                 switch (waypoint->arrive) { | ||||
|                     case FP_GameWaypointArrive_Default: { | ||||
|                         arrival_threshold = FP_Game_MetersToPixelsNx1(game, 1.f); | ||||
|                         arrival_threshold = FP_Game_MetersToPixelsNx1(game, 0.5f); | ||||
|                     } break; | ||||
| 
 | ||||
|                     case FP_GameWaypointArrive_WhenWithinEntitySize: { | ||||
| @ -1067,14 +1037,11 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input | ||||
|                 } | ||||
| 
 | ||||
|                 // NOTE: We have arrived at the waypoint
 | ||||
|                 if ((entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) && waypoint_entity->type == FP_EntityType_Terry) { | ||||
|                     // NOTE: We had a waypoint to move to Terry because he has
 | ||||
|                     // drawn our aggro and we've arrived at Terry
 | ||||
| 
 | ||||
|                     bool can_attack = !entity->is_dying; | ||||
| 
 | ||||
|                 bool aggro_on_terry      = (entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) && waypoint_entity->type == FP_EntityType_Terry; | ||||
|                 bool club_terry_response = (entity->flags & FP_GameEntityFlag_RespondsToClubTerry) && waypoint_entity->type == FP_EntityType_ClubTerry; | ||||
|                 if (aggro_on_terry || club_terry_response) { | ||||
|                     bool can_attack = !entity->is_dying; // TODO(doyle): State transition needs to check if it's valid to move to making this not necessary
 | ||||
|                     if (can_attack) { | ||||
| 
 | ||||
|                         Dqn_V2 attack_dir_vectors[FP_GameDirection_Count] = {}; | ||||
|                         attack_dir_vectors[FP_GameDirection_Up]           = Dqn_V2_InitNx2(+0, -1); | ||||
|                         attack_dir_vectors[FP_GameDirection_Down]         = Dqn_V2_InitNx2(+0, +1); | ||||
| @ -1117,7 +1084,8 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input | ||||
|                                 entity->direction = best_attack_dir; | ||||
|                             } break; | ||||
| 
 | ||||
|                             case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break; | ||||
|                             case FP_EntityType_Count:     DQN_INVALID_CODE_PATH; break; | ||||
|                             case FP_EntityType_ClubTerry: break; | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
| @ -1195,6 +1163,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input | ||||
|                     FP_GameEntity *mob  = FP_Game_GetEntity(game, link->data); | ||||
|                     mob->waypoints      = FP_SentinelList_Init<FP_GameWaypoint>(game->chunk_pool); | ||||
|                     mob->flags         |= FP_GameEntityFlag_AggrosWhenNearTerry; | ||||
|                     mob->flags         |= FP_GameEntityFlag_RespondsToClubTerry; | ||||
| 
 | ||||
|                     for (FP_GameEntity *waypoint_entity = entity->first_child; waypoint_entity; waypoint_entity = waypoint_entity->next) { | ||||
|                         if ((waypoint_entity->flags & FP_GameEntityFlag_MobSpawnerWaypoint) == 0) | ||||
| @ -1245,7 +1214,8 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input | ||||
|                     case FP_EntityType_Nil:      /*FALLTRHU*/ | ||||
|                     case FP_EntityType_Terry:    /*FALLTRHU*/ | ||||
|                     case FP_EntityType_Merchant: /*FALLTRHU*/ | ||||
|                     case FP_EntityType_Count:    break; | ||||
|                     case FP_EntityType_Count:     break; | ||||
|                     case FP_EntityType_ClubTerry: break; | ||||
|                 } | ||||
| 
 | ||||
|                 if (!permit_attack) | ||||
|  | ||||
							
								
								
									
										33
									
								
								feely_pona.h
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								feely_pona.h
									
									
									
									
									
								
							| @ -21,3 +21,36 @@ struct FP_Meters | ||||
|     Dqn_f32 meters; | ||||
| }; | ||||
| 
 | ||||
| struct FP_GlobalAnimations | ||||
| { | ||||
|     Dqn_String8 terry_walk_idle       = DQN_STRING8("terry_walk_idle"); | ||||
|     Dqn_String8 terry_walk_up         = DQN_STRING8("terry_walk_up"); | ||||
|     Dqn_String8 terry_walk_down       = DQN_STRING8("terry_walk_down"); | ||||
|     Dqn_String8 terry_walk_left       = DQN_STRING8("terry_walk_left"); | ||||
|     Dqn_String8 terry_walk_right      = DQN_STRING8("terry_walk_right"); | ||||
|     Dqn_String8 terry_attack_up       = DQN_STRING8("terry_attack_up"); | ||||
|     Dqn_String8 terry_attack_side     = DQN_STRING8("terry_attack_side"); | ||||
|     Dqn_String8 terry_attack_down     = DQN_STRING8("terry_attack_down"); | ||||
|     Dqn_String8 terry_merchant        = DQN_STRING8("terry_merchant"); | ||||
| 
 | ||||
|     Dqn_String8 smoochie_walk_up      = DQN_STRING8("smoochie_walk_up"); | ||||
|     Dqn_String8 smoochie_walk_down    = DQN_STRING8("smoochie_walk_down"); | ||||
|     Dqn_String8 smoochie_walk_left    = DQN_STRING8("smoochie_walk_left"); | ||||
|     Dqn_String8 smoochie_walk_right   = DQN_STRING8("smoochie_walk_right"); | ||||
|     Dqn_String8 smoochie_attack_down  = DQN_STRING8("smoochie_attack_down"); | ||||
|     Dqn_String8 smoochie_hurt_side    = DQN_STRING8("smoochie_hurt_side"); | ||||
|     Dqn_String8 smoochie_attack_heart = DQN_STRING8("smoochie_attack_heart"); | ||||
|     Dqn_String8 smoochie_death        = DQN_STRING8("smoochie_death"); | ||||
| 
 | ||||
|     Dqn_String8 clinger_attack_down = DQN_STRING8("clinger_attack_down"); | ||||
|     Dqn_String8 clinger_attack_side = DQN_STRING8("clinger_attack_side"); | ||||
|     Dqn_String8 clinger_attack_up   = DQN_STRING8("clinger_attack_up"); | ||||
|     Dqn_String8 clinger_death       = DQN_STRING8("clinger_death"); | ||||
|     Dqn_String8 clinger_walk_up     = DQN_STRING8("clinger_walk_up"); | ||||
|     Dqn_String8 clinger_walk_down   = DQN_STRING8("clinger_walk_down"); | ||||
| 
 | ||||
|     Dqn_String8 club_terry_alive  = DQN_STRING8("club_terry_alive"); | ||||
|     Dqn_String8 club_terry_dark   = DQN_STRING8("club_terry_dark"); | ||||
| } | ||||
| g_anim_names; | ||||
| 
 | ||||
|  | ||||
| @ -14,6 +14,13 @@ static void FP_Entity_AddDebugEditorFlags(FP_Game *game, FP_GameEntityHandle han | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static Dqn_f32 FP_Entity_CalcSpriteScaleForDesiredHeight(FP_Game *game, FP_Meters height, Dqn_Rect sprite_rect) | ||||
| { | ||||
|     Dqn_f32 sprite_in_meters = FP_Game_PixelsToMetersNx1(game, sprite_rect.size.y); | ||||
|     Dqn_f32 result           = height.meters / sprite_in_meters; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| static FP_GameEntityHandle FP_Entity_CreateWaypointF(FP_Game *game, Dqn_V2 pos, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) | ||||
| { | ||||
|     va_list args; | ||||
| @ -48,7 +55,8 @@ static FP_GameEntityHandle FP_Entity_CreateClinger(FP_Game *game, Dqn_V2 pos, DQ | ||||
|     entity->is_dying             = false; | ||||
|     entity->local_pos            = pos; | ||||
|     entity->sprite_height.meters = 1.6f; | ||||
|     entity->local_hit_box_size   = FP_Game_MetersToPixelsNx2(game, 0.4f, 1.7f); | ||||
| 
 | ||||
|     entity->local_hit_box_size   = FP_Game_MetersToPixelsNx2(game, 0.4f, entity->sprite_height.meters * .5f); | ||||
|     FP_Entity_AddDebugEditorFlags(game, entity->handle); | ||||
|     entity->flags              |= FP_GameEntityFlag_NonTraversable; | ||||
|     entity->flags              |= FP_GameEntityFlag_Attackable; | ||||
| @ -68,7 +76,7 @@ static FP_GameEntityHandle FP_Entity_CreateSmoochie(FP_Game *game, Dqn_V2 pos, D | ||||
|     entity->is_dying             = false; | ||||
|     entity->local_pos            = pos; | ||||
|     entity->sprite_height.meters = 1.6f; | ||||
|     entity->local_hit_box_size   = FP_Game_MetersToPixelsNx2(game, 0.4f, 1.6f); | ||||
|     entity->local_hit_box_size   = FP_Game_MetersToPixelsNx2(game, 0.4f, entity->sprite_height.meters * .6f); | ||||
|     FP_Entity_AddDebugEditorFlags(game, entity->handle); | ||||
|     entity->flags              |= FP_GameEntityFlag_NonTraversable; | ||||
|     entity->flags              |= FP_GameEntityFlag_Attackable; | ||||
| @ -131,7 +139,7 @@ static FP_GameEntityHandle FP_Entity_CreateTerry(FP_Game *game, Dqn_V2 pos, DQN_ | ||||
|     entity->type                 = FP_EntityType_Terry; | ||||
|     entity->local_pos            = pos; | ||||
|     entity->sprite_height.meters = 1.8f; | ||||
|     entity->local_hit_box_size   = FP_Game_MetersToPixelsNx2(game, 0.5f, entity->sprite_height.meters); | ||||
|     entity->local_hit_box_size   = FP_Game_MetersToPixelsNx2(game, 0.5f, entity->sprite_height.meters * .6f); | ||||
|     FP_Entity_AddDebugEditorFlags(game, result); | ||||
|     entity->flags              |= FP_GameEntityFlag_NonTraversable; | ||||
|     entity->flags              |= FP_GameEntityFlag_Attackable; | ||||
| @ -166,8 +174,14 @@ static FP_GameEntityHandle FP_Entity_CreateClubTerry(FP_Game *game, Dqn_V2 pos, | ||||
| 
 | ||||
|     entity->type                 = FP_EntityType_ClubTerry; | ||||
|     entity->local_pos            = pos; | ||||
|     entity->local_hit_box_size   = Dqn_V2_InitNx2(50, 50); | ||||
|     entity->sprite_height.meters = 3.66f; | ||||
|     entity->sprite_height.meters = 4.f; | ||||
| 
 | ||||
|     TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->club_terry_sprite_sheet, g_anim_names.club_terry_alive); | ||||
|     Dqn_Rect sprite_rect                   = game->club_terry_sprite_sheet.rects.data[sprite_anim->index]; | ||||
|     Dqn_f32 size_scale                     = FP_Entity_CalcSpriteScaleForDesiredHeight(game, entity->sprite_height, sprite_rect); | ||||
|     Dqn_V2 sprite_rect_scaled              = sprite_rect.size * size_scale; | ||||
| 
 | ||||
|     entity->local_hit_box_size   = Dqn_V2_InitNx2(sprite_rect_scaled.w, sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); | ||||
|     FP_Entity_AddDebugEditorFlags(game, result); | ||||
|     entity->flags              |= FP_GameEntityFlag_NonTraversable; | ||||
| 
 | ||||
|  | ||||
| @ -651,19 +651,19 @@ static Dqn_V2 FP_Game_CalcWaypointWorldPos(FP_Game *game, FP_GameWaypoint const | ||||
|             Dqn_Rect entity_rect = FP_Game_CalcEntityWorldHitBox(game, waypoint_entity->handle); | ||||
|             switch (waypoint->type_direction) { | ||||
|                 case FP_GameDirection_Up: { | ||||
|                     result = Dqn_V2_InitNx2(entity_rect.pos.x + entity_rect.size.w * .5f, entity_rect.pos.y - entity_rect.size.h * .5f); | ||||
|                     result = Dqn_V2_InitNx2(entity_rect.pos.x + entity_rect.size.w * .5f, entity_rect.pos.y + entity_rect.size.h * .1f); | ||||
|                 } break; | ||||
| 
 | ||||
|                 case FP_GameDirection_Down: { | ||||
|                     result = Dqn_V2_InitNx2(entity_rect.pos.x + entity_rect.size.w * .5f, entity_rect.pos.y + entity_rect.size.h + (entity_rect.size.h * .5f)); | ||||
|                     result = Dqn_V2_InitNx2(entity_rect.pos.x + entity_rect.size.w * .5f, entity_rect.pos.y + entity_rect.size.h + entity_rect.size.h * .1f); | ||||
|                 } break; | ||||
| 
 | ||||
|                 case FP_GameDirection_Left: { | ||||
|                     result = Dqn_V2_InitNx2(entity_rect.pos.x - entity_rect.size.w * .5f, entity_rect.pos.y + entity_rect.size.h * .5f); | ||||
|                     result = Dqn_V2_InitNx2(entity_rect.pos.x - entity_rect.size.w * .1f, entity_rect.pos.y + entity_rect.size.h * .5f); | ||||
|                 } break; | ||||
| 
 | ||||
|                 case FP_GameDirection_Right: { | ||||
|                     result = Dqn_V2_InitNx2(entity_rect.pos.x + entity_rect.size.w + entity_rect.size.w * .5f, entity_rect.pos.y + entity_rect.size.h * .5f); | ||||
|                     result = Dqn_V2_InitNx2(entity_rect.pos.x + entity_rect.size.w + entity_rect.size.w * .1f, entity_rect.pos.y + entity_rect.size.h * .5f); | ||||
|                 } break; | ||||
| 
 | ||||
|                 case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; | ||||
| @ -674,4 +674,31 @@ static Dqn_V2 FP_Game_CalcWaypointWorldPos(FP_Game *game, FP_GameWaypoint const | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| FP_GameFindClosestEntityResult FP_Game_FindClosestEntityWithType(FP_Game *game, FP_GameEntityHandle src_entity_handle, FP_EntityType type) | ||||
| { | ||||
|     FP_GameFindClosestEntityResult result = {}; | ||||
|     FP_GameEntity *src_entity             = FP_Game_GetEntity(game, src_entity_handle); | ||||
|     if (FP_Game_IsNilEntity(src_entity)) | ||||
|         return result; | ||||
| 
 | ||||
|     Dqn_V2 src_pos      = FP_Game_CalcEntityWorldPos(game, src_entity_handle); | ||||
|     result.dist_squared = DQN_F32_MAX; | ||||
|     result.pos          = Dqn_V2_InitNx1(DQN_F32_MAX); | ||||
| 
 | ||||
|     for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { | ||||
|         FP_GameEntity *it_entity = it.entity; | ||||
|         if (it_entity->type != type) | ||||
|             continue; | ||||
| 
 | ||||
|         Dqn_V2 pos   = FP_Game_CalcEntityWorldPos(game, it_entity->handle); | ||||
|         Dqn_f32 dist = Dqn_V2_LengthSq_V2x2(pos, src_pos); | ||||
|         if (dist < result.dist_squared) { | ||||
|             result.pos          = pos; | ||||
|             result.dist_squared = dist; | ||||
|             result.entity       = it_entity->handle; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -16,6 +16,7 @@ enum FP_GameEntityFlag | ||||
|     FP_GameEntityFlag_MobSpawnerWaypoint                  = 1 << 8, | ||||
|     FP_GameEntityFlag_AggrosWhenNearTerry                 = 1 << 9, | ||||
|     FP_GameEntityFlag_Attackable                          = 1 << 10, | ||||
|     FP_GameEntityFlag_RespondsToClubTerry                 = 1 << 11, | ||||
| }; | ||||
| 
 | ||||
| enum FP_GameShapeType | ||||
| @ -151,8 +152,8 @@ struct FP_GameEntity | ||||
| 
 | ||||
|     Dqn_V2                                attack_box_size; | ||||
|     Dqn_V2                                attack_box_offset; | ||||
|     bool                                  attack_processed;  | ||||
|     bool                                  is_dying;  | ||||
|     bool                                  attack_processed; | ||||
|     bool                                  is_dying; | ||||
| 
 | ||||
|     Dqn_FArray<Dqn_V2, 8>                 spawner_waypoints; | ||||
|     FP_SentinelList<FP_GameEntityHandle>  spawn_list; | ||||
| @ -235,3 +236,11 @@ struct FP_GameAStarNode | ||||
|     Dqn_V2I   came_from; | ||||
|     bool      non_traversable; | ||||
| }; | ||||
| 
 | ||||
| struct FP_GameFindClosestEntityResult | ||||
| { | ||||
|     FP_GameEntityHandle entity; | ||||
|     Dqn_f32             dist_squared; | ||||
|     Dqn_V2              pos; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user