#if defined(__clang__) #pragma once #include "feely_pona_unity.h" #endif enum FP_GameEntityFlag { FP_GameEntityFlag_Clickable = 1 << 0, FP_GameEntityFlag_MoveByKeyboard = 1 << 1, FP_GameEntityFlag_MoveByMouse = 1 << 2, FP_GameEntityFlag_MoveByGamepad = 1 << 3, FP_GameEntityFlag_DrawHitBox = 1 << 4, FP_GameEntityFlag_DeriveHitBoxFromChildrenBoundingBox = 1 << 5, FP_GameEntityFlag_NonTraversable = 1 << 6, FP_GameEntityFlag_MobSpawner = 1 << 7, FP_GameEntityFlag_MobSpawnerWaypoint = 1 << 8, FP_GameEntityFlag_AggrosWhenNearTerry = 1 << 9, FP_GameEntityFlag_Attackable = 1 << 10, FP_GameEntityFlag_RespondsToClubTerry = 1 << 11, }; enum FP_GameShapeType { FP_GameShapeType_None, FP_GameShapeType_Circle, FP_GameShapeType_Rect, FP_GameShapeType_Line, }; struct FP_GameShape { FP_GameShapeType type; Dqn_V2 p1; Dqn_V2 p2; Dqn_V4 colour; Dqn_f32 line_thickness; Dqn_f32 circle_radius; TELY_RenderShapeMode render_mode; }; const uint64_t FP_GAME_ENTITY_HANDLE_GENERATION_MASK = 0xFFFF'0000'0000'0000; const uint64_t FP_GAME_ENTITY_HANDLE_GENERATION_RSHIFT = 48; const uint64_t FP_GAME_ENTITY_HANDLE_GENERATION_MAX = FP_GAME_ENTITY_HANDLE_GENERATION_MASK >> FP_GAME_ENTITY_HANDLE_GENERATION_RSHIFT; const uint64_t FP_GAME_ENTITY_HANDLE_INDEX_MASK = 0x0000'FFFF'FFFF'FFFF; const uint64_t FP_GAME_ENTITY_HANDLE_INDEX_MAX = FP_GAME_ENTITY_HANDLE_INDEX_MASK - 1; struct FP_GameEntityHandle { uint64_t id; }; enum FP_GameWaypointArrive { // Considered arrived when within 1 meter of the target (`value` is ignored). FP_GameWaypointArrive_Default, // If set, we consider the entity as arriving at the waypoint when it's // distance to the target is: // // `arrived = dist <= (entity_hit_box_size * value)` // // A value of 0 for example means we are considered arrived when the entity // is positioned exactly on top of the target's position. FP_GameWaypointArrive_WhenWithinEntitySize, }; enum FP_GameWaypointType { FP_GameWaypointType_At, // Move to the specified entity FP_GameWaypointType_Side, // Move to the side of the entity specified by the direction }; enum FP_GameDirection { FP_GameDirection_Up, FP_GameDirection_Down, FP_GameDirection_Left, FP_GameDirection_Right, FP_GameDirection_Count, }; struct FP_GameWaypoint { FP_GameWaypointType type; FP_GameDirection type_direction; FP_GameEntityHandle entity; FP_GameWaypointArrive arrive; Dqn_f32 value; }; struct FP_GameEntitySpawnList { FP_GameEntityHandle entity; FP_GameEntitySpawnList *next; FP_GameEntitySpawnList *prev; }; struct FP_GameEntityActionSprite { TELY_AssetSpriteSheet *sheet; TELY_AssetSpriteAnimation *anim; }; uint64_t const FP_GAME_ENTITY_ACTION_INFINITE_TIMER = UINT64_MAX; struct FP_GameEntityAction { uint32_t state; uint32_t next_state; TELY_AssetAnimatedSprite sprite; uint64_t started_at_clock_ms; uint64_t end_at_clock_ms; }; struct FP_GameRenderSprite { Dqn_V2 offset; TELY_AssetAnimatedSprite asset; bool loop; FP_Meters height; uint64_t started_at_clock_ms; }; struct FP_GameEntity { FP_GameEntity *next; FP_GameEntity *prev; FP_GameEntity *first_child; FP_GameEntity *last_child; FP_GameEntity *parent; FP_EntityType type; Dqn_String8 name; FP_GameEntityHandle handle; // The target size to render the sprite in meters. The width of the sprite // is scaled uniformly with respect to the height. FP_Meters sprite_height; FP_GameEntityAction action; Dqn_V2 velocity; // Extra animations that are to be executed, but, don't affect the state // of the entity. For example, when Smoochie attacks, we have a heart // animation that is a seperate sprite that will play out. Dqn_FArray extra_cosmetic_anims; FP_SentinelList waypoints; FP_GameEntityHandle aggro_slot[FP_GameDirection_Count]; // NOTE: The entity hit box is positioned at the center of the entity. Dqn_V2 local_hit_box_size; Dqn_V2 local_hit_box_offset; Dqn_V2 attack_box_size; Dqn_V2 attack_box_offset; bool attack_processed; bool is_dying; Dqn_FArray spawner_waypoints; FP_SentinelList spawn_list; uint64_t next_spawn_timestamp_s; uint64_t spawn_cap; uint64_t flags; uint64_t hp; FP_GameDirection direction; Dqn_V2 local_pos; Dqn_f64 alive_time_s; Dqn_FArray shapes; }; struct FP_GameEntityIterator { bool init; Dqn_usize iteration_count; FP_GameEntity *entity; FP_GameEntity *last_visited; FP_GameEntity *entity_parent; FP_GameEntity *entity_next; FP_GameEntity *entity_first_child; }; struct FP_GameCamera { Dqn_V2 world_pos; Dqn_f32 rotate_rads; Dqn_V2 scale; }; struct FP_Game { Dqn_f32 delta_s_accumulator; uint16_t tile_size; TELY_ChunkPool *chunk_pool; TELY_AssetFontHandle inter_regular_font; TELY_AssetFontHandle inter_italic_font; TELY_AssetFontHandle jetbrains_mono_font; TELY_AssetAudioHandle test_audio; Dqn_Slice hero_sprite_anims; TELY_AssetSpriteSheet hero_sprite_sheet; Dqn_FArray parent_entity_stack; Dqn_VArray entities; TELY_AssetSpriteSheet terry_sprite_sheet; TELY_AssetSpriteSheet smoochie_sprite_sheet; TELY_AssetSpriteSheet terry_merchant_sprite_sheet; TELY_AssetSpriteSheet clinger_sprite_sheet; TELY_AssetSpriteSheet club_terry_sprite_sheet; FP_GameEntity *root_entity; FP_GameEntity *entity_free_list; FP_GameEntityHandle player; FP_GameEntityHandle clicked_entity; FP_GameEntityHandle hot_entity; FP_GameEntityHandle active_entity; FP_GameEntityHandle prev_clicked_entity; FP_GameEntityHandle prev_hot_entity; FP_GameEntityHandle prev_active_entity; FP_GameCamera camera; TELY_RFui rfui; Dqn_f32 meters_to_pixels; uint64_t clock_ms; Dqn_PCG32 rng; }; struct FP_GameAStarNode { Dqn_usize cost; Dqn_usize heuristic; Dqn_V2I tile; Dqn_V2I came_from; bool non_traversable; }; struct FP_GameFindClosestEntityResult { FP_GameEntityHandle entity; Dqn_f32 dist_squared; Dqn_V2 pos; };