feely_pona/feely_pona_game.h

394 lines
14 KiB
C
Raw Normal View History

#if defined(__clang__)
#pragma once
#include "feely_pona_unity.h"
#endif
2023-09-23 02:33:59 +00:00
enum FP_GameEntityFlag
2023-09-17 10:24:07 +00:00
{
2023-09-23 02:33:59 +00:00
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,
2023-10-07 14:29:50 +00:00
FP_GameEntityFlag_MobSpawnerWaypoint = 1 << 7,
FP_GameEntityFlag_Aggros = 1 << 8,
FP_GameEntityFlag_Attackable = 1 << 9,
FP_GameEntityFlag_RespondsToBuildings = 1 << 10,
FP_GameEntityFlag_OccupiedInBuilding = 1 << 11,
2023-10-08 08:04:11 +00:00
FP_GameEntityFlag_CameraTracking = 1 << 12,
FP_GameEntityFlag_BuildZone = 1 << 13,
FP_GameEntityFlag_TTL = 1 << 14,
FP_GameEntityFlag_Friendly = 1 << 15,
FP_GameEntityFlag_Foe = 1 << 16,
FP_GameEntityFlag_NoClip = 1 << 17,
FP_GameEntityFlag_RecoversHP = 1 << 18,
2023-09-17 10:24:07 +00:00
};
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,
};
2023-09-29 04:50:40 +00:00
enum FP_GameWaypointType
{
2023-10-07 08:14:09 +00:00
FP_GameWaypointType_At, // Move to the specified entity
FP_GameWaypointType_Side, // Move to the side of the entity specified by the direction
FP_GameWaypointType_ClosestSide, // Move to the side of the entity closest to us
2023-10-09 13:06:59 +00:00
FP_GameWaypointType_Queue, // Queue at the target entity
2023-09-29 04:50:40 +00:00
};
enum FP_GameDirection
{
FP_GameDirection_Up,
FP_GameDirection_Down,
FP_GameDirection_Left,
FP_GameDirection_Right,
FP_GameDirection_Count,
};
2023-09-17 10:24:07 +00:00
struct FP_GameWaypoint
{
2023-09-29 04:50:40 +00:00
FP_GameWaypointType type;
FP_GameDirection type_direction; // Used if type is `FP_GameWaypointType_Side`
FP_GameEntityHandle entity; // The entity to move to
FP_GameWaypointArrive arrive;
Dqn_f32 value; // Used for `arrive` threshold
Dqn_V2 offset; // Used if type is `FP_GameWaypointType_Offset`
2023-09-17 10:24:07 +00:00
};
struct FP_GameEntitySpawnList
{
FP_GameEntityHandle entity;
FP_GameEntitySpawnList *next;
FP_GameEntitySpawnList *prev;
};
2023-09-24 11:54:08 +00:00
struct FP_GameEntityActionSprite
{
TELY_AssetSpriteSheet *sheet;
2023-09-24 11:54:08 +00:00
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;
2023-10-07 14:29:50 +00:00
bool sprite_play_once;
2023-10-07 04:29:56 +00:00
Dqn_f32 sprite_alpha;
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_GameInventory
{
uint32_t airports_base_price;
uint32_t clubs_base_price;
uint32_t kennels_base_price;
uint32_t churchs_base_price;
uint32_t stamina_base_price;
uint32_t health_base_price;
uint32_t mobile_plan_base_price;
uint32_t attack_base_price;
uint8_t airports;
uint8_t clubs;
uint8_t kennels;
uint8_t churchs;
};
2023-10-07 08:14:09 +00:00
enum FP_GameEntityFaction
{
FP_GameEntityFaction_Nil,
FP_GameEntityFaction_Friendly,
FP_GameEntityFaction_Foe,
};
2023-09-17 10:24:07 +00:00
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;
2023-09-25 14:07:39 +00:00
// 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;
2023-09-30 06:51:59 +00:00
FP_Meters base_acceleration_per_s;
2023-10-05 10:10:50 +00:00
Dqn_V2 constant_acceleration_per_s;
Dqn_V2 velocity;
2023-09-17 10:24:07 +00:00
// 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<FP_GameRenderSprite, 2> extra_cosmetic_anims;
FP_SentinelList<FP_GameWaypoint> waypoints;
2023-09-29 04:50:40 +00:00
FP_GameEntityHandle aggro_slot[FP_GameDirection_Count];
2023-09-17 10:24:07 +00:00
FP_GameEntityHandle building_patron;
2023-09-30 06:51:59 +00:00
2023-09-17 10:24:07 +00:00
// 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;
2023-10-01 05:47:40 +00:00
uint64_t last_attack_timestamp;
uint64_t attack_cooldown_ms;
Dqn_FArray<Dqn_V2, 8> spawner_waypoints;
FP_SentinelList<FP_GameEntityHandle> spawn_list;
uint64_t next_spawn_timestamp_s;
uint64_t spawn_cap;
uint64_t flags;
FP_GameDirection direction;
Dqn_V2 local_pos;
Dqn_f64 alive_time_s;
Dqn_FArray<FP_GameShape, 4> shapes;
2023-10-06 10:57:34 +00:00
FP_GameEntityHandle projectile_owner;
2023-10-05 10:10:50 +00:00
uint64_t ttl_end_timestamp;
FP_SentinelList<FP_GameEntityHandle> buildings_visited;
2023-10-06 10:57:34 +00:00
Dqn_usize terry_mobile_data_plan;
Dqn_usize terry_mobile_data_plan_cap;
2023-10-08 09:05:40 +00:00
Dqn_usize clinger_next_dash_timestamp;
2023-10-08 09:51:54 +00:00
bool smoochie_has_teleported;
Dqn_usize smoochie_teleport_timestamp;
2023-10-06 10:57:34 +00:00
Dqn_usize coins;
FP_GameInventory inventory;
2023-10-08 06:35:57 +00:00
uint32_t hp;
uint32_t hp_cap;
uint32_t stamina;
uint32_t stamina_cap;
2023-10-08 08:04:11 +00:00
uint32_t hp_recover_every_n_ticks;
2023-10-08 06:35:57 +00:00
uint32_t base_attack;
2023-10-07 08:14:09 +00:00
bool converted_faction;
FP_GameEntityFaction faction;
uint32_t count_of_entities_targetting_sides[FP_GameDirection_Count];
2023-10-07 14:29:50 +00:00
FP_GameEntityHandle carried_monkey;
2023-10-09 13:06:59 +00:00
Dqn_FArray<FP_GameEntityHandle, 3> building_queue;
uint64_t building_queue_next_sort_timestamp_ms;
FP_GameEntityHandle queued_at_building;
2023-09-17 10:24:07 +00:00
};
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;
};
enum FP_GameAudio
2023-09-30 09:09:15 +00:00
{
FP_GameAudio_TestAudio,
FP_GameAudio_TerryHit,
2023-09-30 13:27:19 +00:00
FP_GameAudio_Smooch,
2023-10-08 05:21:39 +00:00
FP_GameAudio_Woosh,
FP_GameAudio_Ching,
FP_GameAudio_Church,
2023-10-08 08:00:13 +00:00
FP_GameAudio_Plane,
FP_GameAudio_Club,
FP_GameAudio_Dog,
FP_GameAudio_MerchantTerry,
FP_GameAudio_MerchantGhost,
FP_GameAudio_MerchantGym,
FP_GameAudio_MerchantPhone,
2023-10-08 09:10:04 +00:00
FP_GameAudio_Message,
2023-09-30 09:09:15 +00:00
FP_GameAudio_Count,
};
enum FP_GameInGameMenu
{
FP_GameInGameMenu_Nil,
FP_GameInGameMenu_Build,
FP_GameInGameMenu_Merchant,
};
enum FP_GameState
{
FP_GameState_IntroScreen,
FP_GameState_Play,
2023-10-09 10:35:51 +00:00
FP_GameState_Pause,
2023-10-08 05:14:31 +00:00
FP_GameState_WinGame,
2023-10-08 08:04:11 +00:00
FP_GameState_LoseGame,
};
2023-10-08 05:14:31 +00:00
struct FP_GamePlay
2023-09-17 10:24:07 +00:00
{
2023-09-23 02:33:59 +00:00
TELY_ChunkPool *chunk_pool;
2023-10-08 05:14:31 +00:00
uint16_t tile_size;
Dqn_f32 delta_s_accumulator;
Dqn_Arena arena;
2023-09-17 10:24:07 +00:00
Dqn_VArray<FP_GameEntity> entities;
2023-10-08 05:14:31 +00:00
Dqn_FArray<FP_GameEntityHandle, 8> parent_entity_stack;
2023-09-24 11:54:08 +00:00
FP_GameEntity *root_entity;
FP_GameEntity *entity_free_list;
FP_GameEntity *map;
2023-09-24 11:54:08 +00:00
FP_GameEntityHandle player;
FP_GameRenderSprite player_merchant_menu;
uint64_t player_trigger_purchase_upgrade_timestamp;
uint64_t player_trigger_purchase_building_timestamp;
2023-10-08 08:04:11 +00:00
FP_GameEntityHandle heart;
FP_GameEntityHandle merchant_terry;
FP_GameEntityHandle merchant_graveyard;
FP_GameEntityHandle merchant_gym;
FP_GameEntityHandle merchant_phone_company;
2023-09-24 08:05:28 +00:00
2023-09-24 11:54:08 +00:00
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;
2023-09-24 11:54:08 +00:00
FP_GameCamera camera;
2023-09-25 14:07:39 +00:00
Dqn_f32 meters_to_pixels;
uint64_t clock_ms;
uint64_t update_counter;
Dqn_PCG32 rng;
2023-10-02 11:38:36 +00:00
2023-10-05 10:30:56 +00:00
bool debug_ui;
2023-10-08 05:14:31 +00:00
bool god_mode;
FP_GameInGameMenu in_game_menu;
bool build_mode_can_place_building;
2023-10-05 12:09:39 +00:00
Dqn_usize build_mode_building_index;
2023-10-07 09:31:01 +00:00
Dqn_FArray<FP_GameEntityHandle, 4> mob_spawners;
2023-10-07 14:29:50 +00:00
Dqn_FArray<FP_GameEntityHandle, 3> portal_monkeys;
2023-10-07 09:56:14 +00:00
uint32_t current_wave;
uint32_t enemies_per_wave;
uint32_t enemies_spawned_this_wave;
uint64_t wave_cooldown_timestamp_ms;
FP_GameState state;
};
2023-09-23 02:33:59 +00:00
2023-10-08 05:14:31 +00:00
struct FP_Game
{
TELY_AssetFontHandle inter_regular_font_large;
TELY_AssetFontHandle inter_regular_font;
TELY_AssetFontHandle inter_italic_font;
TELY_AssetFontHandle jetbrains_mono_font;
TELY_AssetFontHandle talkco_font;
TELY_AssetFontHandle talkco_font_large;
TELY_AssetAudioHandle audio[FP_GameAudio_Count];
Dqn_Slice<TELY_AssetSpriteAnimation> hero_sprite_anims;
TELY_AssetSpriteSheet hero_sprite_sheet;
TELY_AssetSpriteSheet atlas_sprite_sheet;
TELY_RFui rfui;
FP_GamePlay play;
};
2023-09-23 02:33:59 +00:00
struct FP_GameAStarNode
{
Dqn_usize cost;
Dqn_usize heuristic;
2023-09-23 07:19:36 +00:00
Dqn_V2I tile;
2023-09-23 02:33:59 +00:00
Dqn_V2I came_from;
bool non_traversable;
2023-09-23 02:33:59 +00:00
};
struct FP_GameFindClosestEntityResult
{
FP_GameEntityHandle entity;
Dqn_f32 dist_squared;
Dqn_V2 pos;
};
2023-10-05 12:09:39 +00:00
struct FP_GamePlaceableBuilding
{
FP_EntityType type;
uint32_t state;
};
FP_GamePlaceableBuilding const PLACEABLE_BUILDINGS[] = {
{FP_EntityType_AirportTerry, FP_EntityAirportTerryState_Idle},
{FP_EntityType_ChurchTerry, FP_EntityChurchTerryState_Idle},
{FP_EntityType_ClubTerry, FP_EntityClubTerryState_Idle},
{FP_EntityType_KennelTerry, FP_EntityKennelTerryState_Idle},
};