2018-04-13 21:13:48 +02:00
|
|
|
/*
|
|
|
|
* This software is licensed under the terms of the MIT-License
|
|
|
|
* See COPYING for further information.
|
|
|
|
* ---
|
2019-01-23 21:10:43 +01:00
|
|
|
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
|
|
|
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@alienslab.net>.
|
2018-04-13 21:13:48 +02:00
|
|
|
*/
|
|
|
|
|
2019-01-23 21:10:43 +01:00
|
|
|
#ifndef IGUARD_entity_h
|
|
|
|
#define IGUARD_entity_h
|
|
|
|
|
2018-04-13 21:13:48 +02:00
|
|
|
#include "taisei.h"
|
|
|
|
|
|
|
|
#include "objectpool.h"
|
2019-03-26 17:32:50 +01:00
|
|
|
#include "util/geometry.h"
|
2018-04-13 21:13:48 +02:00
|
|
|
|
|
|
|
#define LAYER_LOW_BITS 16
|
|
|
|
#define LAYER_LOW_MASK ((1 << LAYER_LOW_BITS) - 1)
|
|
|
|
typedef uint32_t drawlayer_t;
|
|
|
|
typedef uint16_t drawlayer_low_t;
|
|
|
|
|
|
|
|
typedef enum DrawLayerID {
|
|
|
|
LAYER_ID_NONE,
|
|
|
|
#define LAYER(x) LAYER_ID_##x,
|
|
|
|
#include "drawlayers.inc.h"
|
|
|
|
} DrawLayerID;
|
|
|
|
|
|
|
|
typedef enum DrawLayer {
|
|
|
|
#define LAYER(x) LAYER_##x = (LAYER_ID_##x << LAYER_LOW_BITS),
|
|
|
|
#include "drawlayers.inc.h"
|
|
|
|
} DrawLayer;
|
|
|
|
|
|
|
|
// NOTE: you can bit-or a drawlayer_low_t value with one of the LAYER_x constants
|
|
|
|
// for sub-layer ordering.
|
|
|
|
|
|
|
|
#define ENT_TYPES \
|
|
|
|
ENT_TYPE(Projectile, ENT_PROJECTILE) \
|
|
|
|
ENT_TYPE(Laser, ENT_LASER) \
|
|
|
|
ENT_TYPE(Enemy, ENT_ENEMY) \
|
|
|
|
ENT_TYPE(Boss, ENT_BOSS) \
|
|
|
|
ENT_TYPE(Player, ENT_PLAYER) \
|
|
|
|
ENT_TYPE(Item, ENT_ITEM) \
|
|
|
|
|
|
|
|
typedef enum EntityType {
|
|
|
|
_ENT_TYPE_ENUM_BEGIN,
|
|
|
|
#define ENT_TYPE(typename, id) id, _ENT_TYPEID_##typename = id,
|
|
|
|
ENT_TYPES
|
|
|
|
#undef ENT_TYPE
|
|
|
|
_ENT_TYPE_ENUM_END,
|
|
|
|
} EntityType;
|
|
|
|
|
|
|
|
typedef struct EntityInterface EntityInterface;
|
|
|
|
typedef struct EntityListNode EntityListNode;
|
2018-07-30 09:04:09 +02:00
|
|
|
|
|
|
|
typedef enum DamageType {
|
|
|
|
DMG_UNDEFINED,
|
|
|
|
DMG_ENEMY_SHOT,
|
|
|
|
DMG_ENEMY_COLLISION,
|
|
|
|
DMG_PLAYER_SHOT,
|
|
|
|
DMG_PLAYER_BOMB,
|
2019-02-22 00:56:03 +01:00
|
|
|
DMG_PLAYER_DISCHARGE,
|
2018-07-30 09:04:09 +02:00
|
|
|
} DamageType;
|
|
|
|
|
2019-02-22 00:56:03 +01:00
|
|
|
#define DAMAGETYPE_IS_PLAYER(dmg) (\
|
|
|
|
(dmg) == DMG_PLAYER_SHOT || \
|
|
|
|
(dmg) == DMG_PLAYER_BOMB || \
|
|
|
|
(dmg) == DMG_PLAYER_DISCHARGE \
|
|
|
|
)
|
|
|
|
|
2018-07-30 09:04:09 +02:00
|
|
|
typedef enum DamageResult {
|
|
|
|
DMG_RESULT_OK,
|
|
|
|
DMG_RESULT_IMMUNE,
|
|
|
|
DMG_RESULT_INAPPLICABLE,
|
|
|
|
} DamageResult;
|
|
|
|
|
|
|
|
typedef struct DamageInfo {
|
|
|
|
float amount;
|
|
|
|
DamageType type;
|
|
|
|
} DamageInfo;
|
|
|
|
|
2018-04-13 21:13:48 +02:00
|
|
|
typedef void (*EntityDrawFunc)(EntityInterface *ent);
|
|
|
|
typedef bool (*EntityPredicate)(EntityInterface *ent);
|
2018-07-30 09:04:09 +02:00
|
|
|
typedef DamageResult (*EntityDamageFunc)(EntityInterface *target, const DamageInfo *damage);
|
2019-01-04 23:59:39 +01:00
|
|
|
typedef void (*EntityDrawHookCallback)(EntityInterface *ent, void *arg);
|
2019-01-10 00:56:33 +01:00
|
|
|
typedef void (*EntityAreaDamageCallback)(EntityInterface *ent, complex ent_origin, void *arg);
|
2018-04-13 21:13:48 +02:00
|
|
|
|
|
|
|
#define ENTITY_INTERFACE_BASE(typename) struct { \
|
2019-04-12 10:36:40 +02:00
|
|
|
LIST_INTERFACE(typename); \
|
2018-04-13 21:13:48 +02:00
|
|
|
EntityType type; \
|
|
|
|
EntityDrawFunc draw_func; \
|
2018-07-30 09:04:09 +02:00
|
|
|
EntityDamageFunc damage_func; \
|
2018-04-13 21:13:48 +02:00
|
|
|
drawlayer_t draw_layer; \
|
|
|
|
uint32_t spawn_id; \
|
|
|
|
uint index; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ENTITY_INTERFACE(typename) union { \
|
|
|
|
EntityInterface entity_interface; \
|
|
|
|
ENTITY_INTERFACE_BASE(typename); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ENTITY_INTERFACE_NAMED(typename, name) union { \
|
2019-04-12 10:36:40 +02:00
|
|
|
LIST_INTERFACE(typename); \
|
2018-04-13 21:13:48 +02:00
|
|
|
EntityInterface entity_interface; \
|
|
|
|
EntityInterface name; \
|
|
|
|
}
|
|
|
|
|
|
|
|
struct EntityInterface {
|
|
|
|
ENTITY_INTERFACE_BASE(EntityInterface);
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline attr_must_inline const char* ent_type_name(EntityType type) {
|
|
|
|
switch(type) {
|
|
|
|
#define ENT_TYPE(typename, id) case id: return #id;
|
|
|
|
ENT_TYPES
|
|
|
|
#undef ENT_TYPE
|
|
|
|
default: return "ENT_INVALID";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ENT_TYPE_ID(typename) (_ENT_TYPEID_##typename)
|
|
|
|
|
|
|
|
#ifdef USE_GNU_EXTENSIONS
|
2019-02-02 12:25:06 +01:00
|
|
|
#define ENT_CAST(ent, typename) (__extension__ ({ \
|
|
|
|
__auto_type _ent = ent; \
|
|
|
|
static_assert(__builtin_types_compatible_p(EntityInterface, __typeof__(*(_ent))), \
|
2018-04-13 21:13:48 +02:00
|
|
|
"Expression is not an EntityInterface pointer"); \
|
|
|
|
static_assert(__builtin_types_compatible_p(EntityInterface, __typeof__(((typename){}).entity_interface)), \
|
|
|
|
#typename " doesn't implement EntityInterface"); \
|
|
|
|
static_assert(__builtin_offsetof(typename, entity_interface) == 0, \
|
|
|
|
"entity_interface has non-zero offset in " #typename); \
|
2019-02-02 12:25:06 +01:00
|
|
|
IF_DEBUG(if(_ent->type != _ENT_TYPEID_##typename) { \
|
|
|
|
log_fatal("Invalid entity cast from %s to " #typename, ent_type_name(_ent->type)); \
|
2019-01-26 15:22:02 +01:00
|
|
|
}); \
|
2019-02-02 12:25:06 +01:00
|
|
|
CASTPTR_ASSUME_ALIGNED(_ent, typename); \
|
2018-04-13 21:13:48 +02:00
|
|
|
}))
|
|
|
|
#else
|
2019-02-02 12:25:06 +01:00
|
|
|
#define ENT_CAST(ent, typename) CASTPTR_ASSUME_ALIGNED(ent, typename)
|
2018-04-13 21:13:48 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
void ent_init(void);
|
|
|
|
void ent_shutdown(void);
|
2018-07-30 09:04:09 +02:00
|
|
|
void ent_register(EntityInterface *ent, EntityType type) attr_nonnull(1);
|
|
|
|
void ent_unregister(EntityInterface *ent) attr_nonnull(1);
|
2018-04-13 21:13:48 +02:00
|
|
|
void ent_draw(EntityPredicate predicate);
|
2018-07-30 09:04:09 +02:00
|
|
|
DamageResult ent_damage(EntityInterface *ent, const DamageInfo *damage) attr_nonnull(1, 2);
|
2019-01-10 00:56:33 +01:00
|
|
|
void ent_area_damage(complex origin, float radius, const DamageInfo *damage, EntityAreaDamageCallback callback, void *callback_arg) attr_nonnull(3);
|
2019-03-26 16:58:38 +01:00
|
|
|
void ent_area_damage_ellipse(Ellipse ellipse, const DamageInfo *damage, EntityAreaDamageCallback callback, void *callback_arg) attr_nonnull(2);
|
2019-01-04 23:59:39 +01:00
|
|
|
|
|
|
|
void ent_hook_pre_draw(EntityDrawHookCallback callback, void *arg);
|
|
|
|
void ent_unhook_pre_draw(EntityDrawHookCallback callback);
|
|
|
|
void ent_hook_post_draw(EntityDrawHookCallback callback, void *arg);
|
|
|
|
void ent_unhook_post_draw(EntityDrawHookCallback callback);
|
2019-01-23 21:10:43 +01:00
|
|
|
|
|
|
|
#endif // IGUARD_entity_h
|