#if defined(_CLANGD) #pragma once #include "feely_pona_unity.h" #endif static void FP_Entity_AddDebugEditorFlags(FP_Game *game, FP_GameEntityHandle handle) { FP_GameEntity *entity = FP_Game_GetEntity(game, handle); if (!FP_Game_IsNilEntity(entity)) { entity->flags |= FP_GameEntityFlag_Clickable; entity->flags |= FP_GameEntityFlag_MoveByKeyboard; entity->flags |= FP_GameEntityFlag_MoveByMouse; entity->flags |= FP_GameEntityFlag_MoveByGamepad; } } static FP_GameEntityHandle FP_Entity_CreateWaypointF(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->local_pos = pos; entity->local_hit_box_size = Dqn_V2_InitNx1(32); FP_Entity_AddDebugEditorFlags(game, entity->handle); entity->flags |= FP_GameEntityFlag_MobSpawnerWaypoint; return result; } static FP_GameEntityHandle FP_Entity_CreateClinger(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_Clinger; entity->is_dying = false; entity->base_acceleration_per_s.meters = 8.f; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; entity->attack_cooldown_ms = 1000; entity->faction = FP_GameEntityFaction_Foe; entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game->play, 0.7f, entity->sprite_height.meters * .5f); FP_Entity_AddDebugEditorFlags(game, entity->handle); entity->flags |= FP_GameEntityFlag_NonTraversable; entity->flags |= FP_GameEntityFlag_Attackable; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); return result; } static FP_GameEntityHandle FP_Entity_CreateSmoochie(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_Smoochie; entity->base_acceleration_per_s.meters = 8.f; entity->is_dying = false; entity->local_pos = pos; entity->attack_cooldown_ms = 1000; entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game->play, 0.7f, entity->sprite_height.meters * .6f); FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Entity_AddDebugEditorFlags(game, entity->handle); entity->flags |= FP_GameEntityFlag_NonTraversable; entity->flags |= FP_GameEntityFlag_Attackable; entity->faction = FP_GameEntityFaction_Foe; return result; } static FP_GameEntityHandle FP_Entity_CreateCatfish(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_Catfish; entity->base_acceleration_per_s.meters = 8.f; entity->is_dying = false; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); entity->attack_cooldown_ms = 1000; entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game->play, 0.7f, entity->sprite_height.meters * .6f); FP_Entity_AddDebugEditorFlags(game, entity->handle); entity->flags |= FP_GameEntityFlag_NonTraversable; entity->flags |= FP_GameEntityFlag_Attackable; entity->faction = FP_GameEntityFaction_Foe; return result; } static FP_GameEntityHandle FP_Entity_CreateWallAtPos(FP_Game *game, Dqn_Str8 name, Dqn_V2 pos, Dqn_V2 size) { FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, name.data); FP_GameEntityHandle result = entity->handle; entity->local_pos = pos; entity->local_hit_box_size = size; FP_Entity_AddDebugEditorFlags(game, entity->handle); entity->flags |= FP_GameEntityFlag_NonTraversable; FP_GameShape *wall = Dqn_FArray_Make(&entity->shapes, Dqn_ZeroMem_Yes); wall->type = FP_GameShapeType_Rect; wall->p2 = entity->local_hit_box_size; wall->colour = TELY_COLOUR_GREEN_DARK_KHAKI_V4; return result; } static FP_GameEntityHandle FP_Entity_CreatePermittedBuildZone(FP_Game *game, Dqn_V2 pos, Dqn_V2 size, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->local_pos = pos; entity->local_hit_box_size = size; entity->type = FP_EntityType_Nil; entity->flags |= FP_GameEntityFlag_BuildZone; FP_Entity_AddDebugEditorFlags(game, entity->handle); return result; } static FP_GameEntityHandle FP_Entity_CreateMobSpawner(FP_Game *game, Dqn_V2 pos, Dqn_usize spawn_cap, char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_MobSpawner; entity->local_pos = pos; entity->local_hit_box_size = Dqn_V2_InitNx1(32); FP_Entity_AddDebugEditorFlags(game, result); FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); entity->spawn_cap = spawn_cap; entity->spawn_list = FP_SentinelList_Init(game->play.chunk_pool); return result; } static FP_GameEntityHandle FP_Entity_CreateTerryInternal(FP_Game *game, Dqn_V2 pos, bool is_perry, DQN_FMT_ATTRIB char const *fmt, va_list args) { FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; entity->type = is_perry ? FP_EntityType_Perry : FP_EntityType_Terry; entity->local_pos = pos; entity->base_acceleration_per_s.meters = 16.f; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); entity->attack_cooldown_ms = 500; entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game->play, 0.5f, entity->sprite_height.meters * .6f); entity->hp_cap = FP_DEFAULT_DAMAGE * 3; entity->hp = entity->hp_cap; entity->coins = 10; FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_NonTraversable; entity->flags |= FP_GameEntityFlag_Attackable; entity->flags |= FP_GameEntityFlag_CameraTracking; entity->flags |= FP_GameEntityFlag_RecoversHP; entity->flags |= FP_GameEntityFlag_HasShadow; entity->terry_mobile_data_plan_cap = DQN_KILOBYTES(6); entity->terry_mobile_data_plan = entity->terry_mobile_data_plan_cap; entity->faction = FP_GameEntityFaction_Friendly; return result; } static FP_GameEntityHandle FP_Entity_CreateTerry(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntityHandle result = FP_Entity_CreateTerryInternal(game, pos, false /*is_perry*/, fmt, args); va_end(args); return result; } static FP_GameEntityHandle FP_Entity_CreatePerry(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntityHandle result = FP_Entity_CreateTerryInternal(game, pos, true /*is_perry*/, fmt, args); va_end(args); return result; } static FP_GameEntityHandle FP_Entity_CreateMerchantTerry(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_MerchantTerry; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_NonTraversable; TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.merchant_graveyard); Dqn_Rect sprite_rect = game->atlas_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_offset = Dqn_V2_InitNx2(0, sprite_rect_scaled.h * .15f); entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w, sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); return result; } static FP_GameEntityHandle FP_Entity_CreateMerchantGraveyard(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_MerchantGraveyard; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_NonTraversable; TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.merchant_graveyard); Dqn_Rect sprite_rect = game->atlas_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_offset = Dqn_V2_InitNx2(0, sprite_rect_scaled.h * .1f); entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w - (sprite_rect_scaled.w * .3f), sprite_rect_scaled.h - (sprite_rect_scaled.h * .5f)); return result; } static FP_GameEntityHandle FP_Entity_CreateMerchantGym(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_MerchantGym; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_NonTraversable; TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.merchant_gym); Dqn_Rect sprite_rect = game->atlas_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_offset = Dqn_V2_InitNx2(0, sprite_rect_scaled.h * .3f); entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w - (sprite_rect_scaled.w * .3f), sprite_rect_scaled.h - (sprite_rect_scaled.h * .6f)); return result; } static FP_GameEntityHandle FP_Entity_CreateMerchantPhoneCompany(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_MerchantPhoneCompany; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_NonTraversable; TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.merchant_phone_company); Dqn_Rect sprite_rect = game->atlas_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_offset = Dqn_V2_InitNx2(0, sprite_rect_scaled.h * .15f); entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w - (sprite_rect_scaled.w * .3f), sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); return result; } static FP_GameEntityHandle FP_Entity_CreateClubTerry(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_ClubTerry; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_NonTraversable; TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.club_terry_alive); Dqn_Rect sprite_rect = game->atlas_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_offset = Dqn_V2_InitNx2(0, sprite_rect_scaled.h * .1f); entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w, sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); return result; } static FP_GameEntityHandle FP_Entity_CreateHeart(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_Heart; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_NonTraversable; entity->flags |= FP_GameEntityFlag_Attackable; entity->flags |= FP_GameEntityFlag_RecoversHP; entity->hp_cap = FP_DEFAULT_DAMAGE * 32; entity->hp = entity->hp_cap; entity->faction = FP_GameEntityFaction_Friendly; entity->hp_recover_every_n_ticks *= 4; TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.heart); Dqn_Rect sprite_rect = game->atlas_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_offset = Dqn_V2_InitNx2(0, sprite_rect_scaled.h * .15f); entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w - (sprite_rect_scaled.w * .3f), sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); return result; } static FP_GameEntityHandle FP_Entity_CreateChurchTerry(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_ChurchTerry; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_NonTraversable; TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.church_terry_alive); Dqn_Rect sprite_rect = game->atlas_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_offset = Dqn_V2_InitNx2(0, sprite_rect_scaled.h * .1f); entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w, sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); return result; } static FP_GameEntityHandle FP_Entity_CreateKennelTerry(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_KennelTerry; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_NonTraversable; TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.church_terry_alive); Dqn_Rect sprite_rect = game->atlas_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_offset = Dqn_V2_InitNx2(0, sprite_rect_scaled.h * .1f); entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w, sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); return result; } static FP_GameEntityHandle FP_Entity_CreateAirportTerry(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_AirportTerry; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_NonTraversable; TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.church_terry_alive); Dqn_Rect sprite_rect = game->atlas_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_offset = Dqn_V2_InitNx2(0, sprite_rect_scaled.h * .1f); entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w, sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); return result; } static FP_GameEntityHandle FP_Entity_CreatePhoneMessageProjectile(FP_Game *game, FP_GameEntityHandle owner, Dqn_V2 pos, Dqn_V2 velocity, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_PhoneMessageProjectile; entity->constant_acceleration_per_s = velocity; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Entity_AddDebugEditorFlags(game, result); entity->flags |= FP_GameEntityFlag_TTL; entity->local_hit_box_offset = Dqn_V2_InitNx2(0, render_data.render_size.h * .1f); entity->local_hit_box_size = Dqn_V2_InitNx2(render_data.render_size.w, render_data.render_size.h - (render_data.render_size.h * .4f)); entity->attack_box_offset = entity->local_hit_box_offset; entity->attack_box_size = entity->local_hit_box_size; entity->ttl_end_timestamp = game->play.clock_ms + 1000; entity->projectile_owner = owner; entity->faction = FP_GameEntityFaction_Friendly; return result; } static FP_GameEntityHandle FP_Entity_CreatePortalMonkey(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_PortalMonkey; entity->local_pos = pos; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Entity_AddDebugEditorFlags(game, result); entity->local_hit_box_offset = Dqn_V2_InitNx2(0, render_data.render_size.h * .1f); entity->local_hit_box_size = Dqn_V2_InitNx2(render_data.render_size.w, render_data.render_size.h - (render_data.render_size.h * .4f)); return result; } static FP_GameEntityHandle FP_Entity_CreateAirportTerryPlane(FP_Game *game, Dqn_V2 pos, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->type = FP_EntityType_AirportTerryPlane; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); entity->local_pos = pos; entity->flags |= FP_GameEntityFlag_NoClip; FP_Entity_AddDebugEditorFlags(game, result); entity->local_hit_box_offset = Dqn_V2_InitNx2(0, render_data.render_size.h * .1f); entity->local_hit_box_size = Dqn_V2_InitNx2(render_data.render_size.w, render_data.render_size.h - (render_data.render_size.h * .4f)); entity->base_acceleration_per_s.meters = 32.f; return result; } static FP_GameEntityHandle FP_Entity_CreateBillboard(FP_Game *game, Dqn_V2 pos, FP_EntityBillboardState state, DQN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); FP_GameEntityHandle result = entity->handle; va_end(args); entity->action.state = state; entity->action.next_state = state; entity->type = FP_EntityType_Billboard; FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, state, FP_GameDirection_Down); entity->sprite_height = render_data.height; uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); entity->local_pos = pos; FP_Entity_AddDebugEditorFlags(game, result); entity->local_hit_box_offset = Dqn_V2_InitNx2(0, render_data.render_size.h * .1f); entity->local_hit_box_size = Dqn_V2_InitNx2(render_data.render_size.w, render_data.render_size.h - (render_data.render_size.h * .4f)); return result; }