176 lines
7.1 KiB
C++
176 lines
7.1 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <array>
|
|
#include <optional>
|
|
|
|
#include "common.h"
|
|
#include "rng.h"
|
|
|
|
namespace doukutsu_rs
|
|
{
|
|
namespace shared_game_state
|
|
{
|
|
class SharedGameState;
|
|
}
|
|
|
|
namespace player
|
|
{
|
|
class Player;
|
|
}
|
|
}
|
|
|
|
namespace doukutsu_rs::npc
|
|
{
|
|
constexpr int MAX_FALL_SPEED = 0x5ff;
|
|
|
|
struct NPCFlag
|
|
{
|
|
uint16_t value;
|
|
|
|
constexpr NPCFlag(uint16_t value) : value(value) {}
|
|
constexpr NPCFlag() : value(0) {}
|
|
|
|
constexpr bool solid_soft() const { return value & 0x01; }
|
|
constexpr bool ignore_tile_44() const { return value & 0x02; }
|
|
constexpr bool invulnerable() const { return value & 0x04; }
|
|
constexpr bool ignore_solidity() const { return value & 0x08; }
|
|
constexpr bool bouncy() const { return value & 0x10; }
|
|
constexpr bool shootable() const { return value & 0x20; }
|
|
constexpr bool solid_hard() const { return value & 0x40; }
|
|
constexpr bool rear_and_top_not_hurt() const { return value & 0x80; }
|
|
constexpr bool event_when_touched() const { return value & 0x100; }
|
|
constexpr bool event_when_killed() const { return value & 0x200; }
|
|
constexpr bool flag_x400() const { return value & 0x400; }
|
|
constexpr bool appear_when_flag_set() const { return value & 0x800; }
|
|
constexpr bool spawn_facing_right() const { return value & 0x1000; }
|
|
constexpr bool interactable() const { return value & 0x2000; }
|
|
constexpr bool hide_unless_flag_set() const { return value & 0x4000; }
|
|
constexpr bool show_damage() const { return value & 0x8000; }
|
|
|
|
constexpr void set_solid_soft(bool value) { this->value = value ? (this->value | 0x01) : (this->value & ~0x01); }
|
|
constexpr void set_ignore_tile_44(bool value) { this->value = value ? (this->value | 0x02) : (this->value & ~0x02); }
|
|
constexpr void set_invulnerable(bool value) { this->value = value ? (this->value | 0x04) : (this->value & ~0x04); }
|
|
constexpr void set_ignore_solidity(bool value) { this->value = value ? (this->value | 0x08) : (this->value & ~0x08); }
|
|
constexpr void set_bouncy(bool value) { this->value = value ? (this->value | 0x10) : (this->value & ~0x10); }
|
|
constexpr void set_shootable(bool value) { this->value = value ? (this->value | 0x20) : (this->value & ~0x20); }
|
|
constexpr void set_solid_hard(bool value) { this->value = value ? (this->value | 0x40) : (this->value & ~0x40); }
|
|
constexpr void set_rear_and_top_not_hurt(bool value) { this->value = value ? (this->value | 0x80) : (this->value & ~0x80); }
|
|
constexpr void set_event_when_touched(bool value) { this->value = value ? (this->value | 0x100) : (this->value & ~0x100); }
|
|
constexpr void set_event_when_killed(bool value) { this->value = value ? (this->value | 0x200) : (this->value & ~0x200); }
|
|
constexpr void set_flag_x400(bool value) { this->value = value ? (this->value | 0x400) : (this->value & ~0x400); }
|
|
constexpr void set_appear_when_flag_set(bool value) { this->value = value ? (this->value | 0x800) : (this->value & ~0x800); }
|
|
constexpr void set_spawn_facing_right(bool value) { this->value = value ? (this->value | 0x1000) : (this->value & ~0x1000); }
|
|
constexpr void set_interactable(bool value) { this->value = value ? (this->value | 0x2000) : (this->value & ~0x2000); }
|
|
constexpr void set_hide_unless_flag_set(bool value) { this->value = value ? (this->value | 0x4000) : (this->value & ~0x4000); }
|
|
constexpr void set_show_damage(bool value) { this->value = value ? (this->value | 0x8000) : (this->value & ~0x8000); }
|
|
};
|
|
|
|
enum class NPCLayer : uint8_t
|
|
{
|
|
Background = 0,
|
|
Middleground = 1,
|
|
Foreground = 2,
|
|
};
|
|
|
|
class Players
|
|
{
|
|
};
|
|
|
|
class NPCTable
|
|
{
|
|
public:
|
|
};
|
|
|
|
class NPCList;
|
|
|
|
class NPC
|
|
{
|
|
public:
|
|
uint16_t id;
|
|
uint16_t npc_type;
|
|
int32_t x;
|
|
int32_t y;
|
|
int32_t vel_x;
|
|
int32_t vel_y;
|
|
int32_t vel_x2;
|
|
int32_t vel_y2;
|
|
int32_t target_x;
|
|
int32_t target_y;
|
|
int32_t prev_x;
|
|
int32_t prev_y;
|
|
uint16_t exp;
|
|
NPCLayer layer;
|
|
uint8_t size;
|
|
uint16_t shock;
|
|
uint16_t life;
|
|
uint16_t damage;
|
|
uint16_t spritesheet_id;
|
|
common::Condition cond;
|
|
common::Flag flags;
|
|
NPCFlag npc_flags;
|
|
common::Direction direction;
|
|
uint16_t tsc_direction;
|
|
uint16_t parent_id;
|
|
uint16_t action_num;
|
|
uint16_t anim_num;
|
|
uint16_t flag_num;
|
|
uint16_t event_num;
|
|
uint16_t action_counter;
|
|
uint16_t action_counter2;
|
|
uint16_t action_counter3;
|
|
uint16_t anim_counter;
|
|
common::Rect<uint16_t> anim_rect;
|
|
common::Rect<uint32_t> display_bounds;
|
|
common::Rect<uint32_t> hit_bounds;
|
|
rng::Xoroshiro32PlusPlus rng;
|
|
// NumberPopup popup;
|
|
|
|
explicit NPC() : id(0), npc_type(0), x(0), y(0), vel_x(0), vel_y(0), vel_x2(0), vel_y2(0),
|
|
target_x(0), target_y(0), prev_x(0), prev_y(0), exp(0), layer(NPCLayer::Middleground),
|
|
size(0), shock(0), life(0), damage(0), spritesheet_id(0), cond(common::Condition(0)),
|
|
flags(common::Flag(0)), npc_flags(NPCFlag(0)), direction(common::Direction::Left),
|
|
tsc_direction(0), parent_id(0), action_num(0), anim_num(0), flag_num(0), event_num(0),
|
|
action_counter(0), action_counter2(0), action_counter3(0), anim_counter(0),
|
|
anim_rect(common::Rect<uint16_t>{0, 0, 0, 0}), display_bounds(common::Rect<uint32_t>{0, 0, 0, 0}),
|
|
hit_bounds(common::Rect<uint32_t>{0, 0, 0, 0}), rng(rng::Xoroshiro32PlusPlus(0)) {}
|
|
|
|
static NPC create(uint16_t npc_type, NPCTable &table);
|
|
|
|
void init_rng();
|
|
|
|
player::Player &get_closest_player_mut(Players &players);
|
|
player::Player const &get_closest_player_ref(Players const &players) const;
|
|
void face_player(const player::Player &player);
|
|
|
|
void clamp_fall_speed()
|
|
{
|
|
if (vel_y > MAX_FALL_SPEED)
|
|
vel_y = MAX_FALL_SPEED;
|
|
}
|
|
|
|
protected:
|
|
#pragma region NPC AI procedures
|
|
void tick_n254_helicopter(shared_game_state::SharedGameState &state, NPCList &npc_list);
|
|
void tick_n255_helicopter_blades(shared_game_state::SharedGameState &state, NPCList &npc_list);
|
|
void tick_n260_shovel_brigade_caged(shared_game_state::SharedGameState &state, NPCList &npc_list);
|
|
void tick_n261_chie_caged(shared_game_state::SharedGameState &state, NPCList &npc_list, Players &players);
|
|
void tick_n262_chaco_caged(shared_game_state::SharedGameState &state, NPCList &npc_list, Players &players);
|
|
#pragma endregion
|
|
};
|
|
|
|
class NPCList
|
|
{
|
|
private:
|
|
std::array<NPC, 512> npcs;
|
|
uint16_t max_npc;
|
|
|
|
explicit NPCList();
|
|
|
|
public:
|
|
bool spawn(uint16_t min_id, NPC npc);
|
|
bool spawn_at_slot(uint16_t id, NPC npc);
|
|
|
|
std::optional<NPC&> get_npc(size_t id);
|
|
};
|
|
}; |