Refactor entity system (#214)
* Smarter generic entity macros The list of "core" entities is now defined in one macro, and hardcoded _Generic dispatch tables are eliminated * Get rid of "custom" entities All entities are now "first-class". The list of known entity types has been moved to known_entities.h. The system no longer needs to know the definition of all entity structs. * Refactor guts of ENT_BOX/ENT_UNBOX Made the functions inline, Box::ent is now a proper pointer type (but please don't use it directly), ENT_UNBOX returns NULL if the box is "empty" (references NULL entity) * Merge TASK_BIND_UNBOXED with TASK_BIND * s/YoumuMyon/YoumuAMyon for consistency
This commit is contained in:
parent
b3ce65d5ac
commit
e16e2184a3
36 changed files with 473 additions and 369 deletions
|
@ -47,7 +47,7 @@ Boss* create_boss(char *name, char *ani, cmplx pos) {
|
|||
boss->ent.draw_layer = LAYER_BOSS;
|
||||
boss->ent.draw_func = ent_draw_boss;
|
||||
boss->ent.damage_func = ent_damage_boss;
|
||||
ent_register(&boss->ent, ENT_BOSS);
|
||||
ent_register(&boss->ent, ENT_TYPE_ID(Boss));
|
||||
|
||||
// This is not necessary because the default will be set at the start of every attack.
|
||||
// But who knows. Maybe this will be triggered somewhen. If bosses without attacks start
|
||||
|
|
|
@ -34,11 +34,10 @@ enum {
|
|||
BOSS_DEATH_DELAY = 120,
|
||||
};
|
||||
|
||||
typedef struct Boss Boss;
|
||||
typedef struct Attack Attack;
|
||||
typedef struct AttackInfo AttackInfo;
|
||||
|
||||
typedef void (*BossRule)(struct Boss*, int time) attr_nonnull(1);
|
||||
typedef void (*BossRule)(Boss*, int time) attr_nonnull(1);
|
||||
|
||||
typedef enum AttackType {
|
||||
AT_Normal,
|
||||
|
@ -125,8 +124,7 @@ struct Attack {
|
|||
AttackInfo *info; // NULL for attacks created directly through boss_add_attack
|
||||
};
|
||||
|
||||
struct Boss {
|
||||
ENTITY_INTERFACE_NAMED(Boss, ent);
|
||||
DEFINE_ENTITY_TYPE(Boss, {
|
||||
cmplx pos;
|
||||
|
||||
Attack attacks[BOSS_MAX_ATTACKS];
|
||||
|
@ -173,7 +171,7 @@ struct Boss {
|
|||
} hud;
|
||||
|
||||
COEVENTS_ARRAY(defeated) events;
|
||||
};
|
||||
});
|
||||
|
||||
Boss* create_boss(char *name, char *ani, cmplx pos) attr_nonnull(1, 2) attr_returns_nonnull;
|
||||
void free_boss(Boss *boss) attr_nonnull(1);
|
||||
|
|
|
@ -1030,18 +1030,3 @@ DEFINE_EXTERN_TASK(_cancel_task_helper) {
|
|||
cotask_cancel(task);
|
||||
}
|
||||
}
|
||||
|
||||
#include <projectile.h>
|
||||
#include <laser.h>
|
||||
#include <item.h>
|
||||
#include <enemy.h>
|
||||
#include <boss.h>
|
||||
#include <player.h>
|
||||
|
||||
#define ENT_TYPE(typename, id) \
|
||||
typename *_cotask_bind_to_entity_##typename(CoTask *task, typename *ent) { \
|
||||
return ENT_CAST((cotask_bind_to_entity)(task, ent ? &ent->entity_interface : NULL), typename); \
|
||||
}
|
||||
|
||||
ENT_TYPES
|
||||
#undef ENT_TYPE
|
||||
|
|
|
@ -398,8 +398,8 @@ DECLARE_EXTERN_TASK(_cancel_task_helper, { BoxedTask task; });
|
|||
#define TASK_EVENTS(task) cotask_get_events(cotask_unbox(task))
|
||||
#define TASK_MALLOC(size) cotask_malloc(cotask_active(), size)
|
||||
|
||||
#define TASK_HOST_CUSTOM_ENT(ent_struct_type) \
|
||||
ENT_CAST_CUSTOM(cotask_host_entity(cotask_active(), sizeof(ent_struct_type), ENT_CUSTOM), ent_struct_type)
|
||||
#define TASK_HOST_ENT(ent_struct_type) \
|
||||
ENT_CAST(cotask_host_entity(cotask_active(), sizeof(ent_struct_type), ENT_TYPE_ID(ent_struct_type)), ent_struct_type)
|
||||
|
||||
#define TASK_HOST_EVENTS(events_array) \
|
||||
cotask_host_events(cotask_active(), sizeof(events_array)/sizeof(CoEvent), &((events_array)._first_event_))
|
||||
|
@ -410,27 +410,22 @@ DECLARE_EXTERN_TASK(_cancel_task_helper, { BoxedTask task; });
|
|||
#define WAIT_EVENT_OR_DIE(e) cotask_wait_event_or_die((e), NULL)
|
||||
#define STALL cotask_wait(INT_MAX)
|
||||
|
||||
#define ENT_TYPE(typename, id) \
|
||||
struct typename; \
|
||||
struct typename *_cotask_bind_to_entity_##typename(CoTask *task, struct typename *ent) attr_returns_nonnull attr_returns_max_aligned;
|
||||
// first arg of the generated function needs to be the ent, because ENT_UNBOXED_DISPATCH_FUNCTION dispatches on first arg.
|
||||
#define _cotask_emit_bindfunc(typename, ...) \
|
||||
INLINE typename *_cotask_bind_to_entity_##typename(typename *ent, CoTask *task) { \
|
||||
return ENT_CAST((cotask_bind_to_entity)(task, ent ? UNION_CAST(typename*, EntityInterface*, ent) : NULL), typename); \
|
||||
}
|
||||
|
||||
ENT_TYPES
|
||||
#undef ENT_TYPE
|
||||
ENTITIES(_cotask_emit_bindfunc,)
|
||||
#undef _cotask_emit_bindfunc
|
||||
|
||||
#define cotask_bind_to_entity(task, ent) (_Generic((ent), \
|
||||
struct Projectile*: _cotask_bind_to_entity_Projectile, \
|
||||
struct Laser*: _cotask_bind_to_entity_Laser, \
|
||||
struct Enemy*: _cotask_bind_to_entity_Enemy, \
|
||||
struct Boss*: _cotask_bind_to_entity_Boss, \
|
||||
struct Player*: _cotask_bind_to_entity_Player, \
|
||||
struct Item*: _cotask_bind_to_entity_Item, \
|
||||
EntityInterface*: cotask_bind_to_entity \
|
||||
)(task, ent))
|
||||
INLINE EntityInterface *_cotask_bind_to_entity_Entity(EntityInterface *ent, CoTask *task) {
|
||||
return (cotask_bind_to_entity)(task, ent);
|
||||
}
|
||||
|
||||
#define TASK_BIND(box) cotask_bind_to_entity(cotask_active(), ENT_UNBOX(box))
|
||||
#define TASK_BIND_UNBOXED(ent) cotask_bind_to_entity(cotask_active(), ent)
|
||||
#define cotask_bind_to_entity(task, ent) \
|
||||
ENT_UNBOXED_DISPATCH_FUNCTION(_cotask_bind_to_entity_, ent, task)
|
||||
|
||||
#define TASK_BIND_CUSTOM(box, type) ENT_CAST_CUSTOM((cotask_bind_to_entity)(cotask_active(), ENT_UNBOX(box)), type)
|
||||
#define TASK_BIND_UNBOXED_CUSTOM(ent, type) ENT_CAST_CUSTOM((cotask_bind_to_entity)(cotask_active(), &(ent)->entity_interface), type)
|
||||
#define TASK_BIND(ent_or_box) cotask_bind_to_entity(cotask_active(), ENT_UNBOX_OR_PASSTHROUGH(ent_or_box))
|
||||
|
||||
#endif // IGUARD_coroutine_h
|
||||
|
|
|
@ -109,7 +109,7 @@ Enemy *create_enemy_p(EnemyList *enemies, cmplx pos, float hp, EnemyVisualRule v
|
|||
|
||||
coevent_init(&e->events.killed);
|
||||
fix_pos0_visual(e);
|
||||
ent_register(&e->ent, ENT_ENEMY);
|
||||
ent_register(&e->ent, ENT_TYPE_ID(Enemy));
|
||||
|
||||
enemy_call_logic_rule(e, EVENT_BIRTH);
|
||||
return e;
|
||||
|
|
23
src/enemy.h
23
src/enemy.h
|
@ -22,12 +22,17 @@
|
|||
#define ENEMY_DEBUG
|
||||
#endif
|
||||
|
||||
#ifdef ENEMY_DEBUG
|
||||
#define IF_ENEMY_DEBUG(...) __VA_ARGS__
|
||||
#else
|
||||
#define IF_ENEMY_DEBUG(...)
|
||||
#endif
|
||||
|
||||
#define ENEMY_HURT_RADIUS 7
|
||||
|
||||
typedef struct Enemy Enemy;
|
||||
typedef LIST_ANCHOR(Enemy) EnemyList;
|
||||
typedef int (*EnemyLogicRule)(struct Enemy*, int t);
|
||||
typedef void (*EnemyVisualRule)(struct Enemy*, int t, bool render);
|
||||
typedef int (*EnemyLogicRule)(Enemy*, int t);
|
||||
typedef void (*EnemyVisualRule)(Enemy*, int t, bool render);
|
||||
|
||||
enum {
|
||||
ENEMY_IMMUNE = -9000,
|
||||
|
@ -35,9 +40,7 @@ enum {
|
|||
ENEMY_KILLED = -9002,
|
||||
};
|
||||
|
||||
struct Enemy {
|
||||
ENTITY_INTERFACE_NAMED(Enemy, ent);
|
||||
|
||||
DEFINE_ENTITY_TYPE(Enemy, {
|
||||
cmplx pos;
|
||||
cmplx pos0;
|
||||
cmplx pos0_visual;
|
||||
|
@ -64,10 +67,10 @@ struct Enemy {
|
|||
|
||||
bool moving;
|
||||
|
||||
#ifdef ENEMY_DEBUG
|
||||
DebugInfo debug;
|
||||
#endif
|
||||
};
|
||||
IF_ENEMY_DEBUG(
|
||||
DebugInfo debug;
|
||||
)
|
||||
});
|
||||
|
||||
#define create_enemy4c(p,h,d,l,a1,a2,a3,a4) create_enemy_p(&global.enemies,p,h,d,l,a1,a2,a3,a4)
|
||||
#define create_enemy3c(p,h,d,l,a1,a2,a3) create_enemy_p(&global.enemies,p,h,d,l,a1,a2,a3,0)
|
||||
|
|
30
src/entity.c
30
src/entity.c
|
@ -37,6 +37,7 @@ static void add_hook(EntityDrawHookList *list, EntityDrawHookCallback cb, void *
|
|||
EntityDrawHook *hook = calloc(1, sizeof(*hook));
|
||||
hook->callback = cb;
|
||||
hook->arg = arg;
|
||||
|
||||
alist_append(list, hook);
|
||||
}
|
||||
|
||||
|
@ -227,32 +228,3 @@ void ent_hook_post_draw(EntityDrawHookCallback callback, void *arg) {
|
|||
void ent_unhook_post_draw(EntityDrawHookCallback callback) {
|
||||
remove_hook(&entities.hooks.post_draw, callback);
|
||||
}
|
||||
|
||||
BoxedEntity _ent_box_Entity(EntityInterface *ent) {
|
||||
BoxedEntity h;
|
||||
h.ent = (uintptr_t)ent;
|
||||
h.spawn_id = ent->spawn_id;
|
||||
return h;
|
||||
}
|
||||
|
||||
EntityInterface *_ent_unbox_Entity(BoxedEntity box) {
|
||||
EntityInterface *e = (EntityInterface*)box.ent;
|
||||
|
||||
if(e->spawn_id == box.spawn_id) {
|
||||
return e;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define ENT_TYPE(typename, id) \
|
||||
Boxed##typename _ent_box_##typename(struct typename *ent) { \
|
||||
return (Boxed##typename) { .as_generic = _ent_box_Entity(&ent->entity_interface) };\
|
||||
} \
|
||||
struct typename *_ent_unbox_##typename(Boxed##typename box) { \
|
||||
EntityInterface *e = _ent_unbox_Entity(box.as_generic); \
|
||||
return e ? ENT_CAST(e, typename) : NULL; \
|
||||
}
|
||||
|
||||
ENT_TYPES
|
||||
#undef ENT_TYPE
|
||||
|
|
159
src/entity.h
159
src/entity.h
|
@ -14,6 +14,7 @@
|
|||
#include "objectpool.h"
|
||||
#include "util/geometry.h"
|
||||
#include "util/macrohax.h"
|
||||
#include "known_entities.h"
|
||||
|
||||
#define LAYER_LOW_BITS 16
|
||||
#define LAYER_LOW_MASK ((1 << LAYER_LOW_BITS) - 1)
|
||||
|
@ -34,22 +35,17 @@ typedef enum DrawLayer {
|
|||
// NOTE: you can bit-or a drawlayer_low_t value with one of the LAYER_x constants
|
||||
// for sub-layer ordering.
|
||||
|
||||
typedef struct CustomEntity CustomEntity;
|
||||
#define ENT_EMIT_TYPEDEFS(typename, ...) typedef struct typename typename;
|
||||
ENTITIES(ENT_EMIT_TYPEDEFS,)
|
||||
#undef ENT_EMIT_TYPEDEFS
|
||||
|
||||
#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) \
|
||||
ENT_TYPE(CustomEntity, ENT_CUSTOM) \
|
||||
#define ENT_TYPE_ID(typename) ENT_TYPEID_##typename
|
||||
|
||||
typedef enum EntityType {
|
||||
_ENT_TYPE_ENUM_BEGIN,
|
||||
#define ENT_TYPE(typename, id) id, _ENT_TYPEID_##typename = id,
|
||||
ENT_TYPES
|
||||
#undef ENT_TYPE
|
||||
#define ENT_EMIT_ENUMS(typename, ...) ENT_TYPE_ID(typename),
|
||||
ENTITIES(ENT_EMIT_ENUMS,)
|
||||
#undef ENT_EMIT_ENUMS
|
||||
_ENT_TYPE_ENUM_END,
|
||||
} EntityType;
|
||||
|
||||
|
@ -91,12 +87,12 @@ typedef void (*EntityAreaDamageCallback)(EntityInterface *ent, cmplx ent_origin,
|
|||
|
||||
#define ENTITY_INTERFACE_BASE(typename) struct { \
|
||||
LIST_INTERFACE(typename); \
|
||||
EntityType type; \
|
||||
EntityDrawFunc draw_func; \
|
||||
EntityDamageFunc damage_func; \
|
||||
drawlayer_t draw_layer; \
|
||||
uint32_t spawn_id; \
|
||||
uint index; \
|
||||
EntityType type; \
|
||||
}
|
||||
|
||||
#define ENTITY_INTERFACE(typename) union { \
|
||||
|
@ -114,42 +110,31 @@ struct EntityInterface {
|
|||
ENTITY_INTERFACE_BASE(EntityInterface);
|
||||
};
|
||||
|
||||
struct CustomEntity {
|
||||
ENTITY_INTERFACE(CustomEntity);
|
||||
};
|
||||
#define DEFINE_ENTITY_TYPE(typename, ...) \
|
||||
struct typename { \
|
||||
ENTITY_INTERFACE_NAMED(typename, ent); \
|
||||
struct __VA_ARGS__; \
|
||||
}
|
||||
|
||||
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_HANDLE_CASE(typename, ...) case ENT_TYPE_ID(typename): return #typename;
|
||||
ENTITIES(ENT_HANDLE_CASE,)
|
||||
#undef ENT_HANDLE_CASE
|
||||
default: return "<INVALID>";
|
||||
}
|
||||
}
|
||||
|
||||
#define ENT_TYPE_ID(typename) (_ENT_TYPEID_##typename)
|
||||
|
||||
#ifdef USE_GNU_EXTENSIONS
|
||||
#define _internal_ENT_CAST(ent, typename, ent_type_id) (__extension__ ({ \
|
||||
#define ENT_CAST(ent, typename) (__extension__ ({ \
|
||||
__auto_type _ent = ent; \
|
||||
static_assert(__builtin_types_compatible_p(EntityInterface, __typeof__(*(_ent))), \
|
||||
"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); \
|
||||
IF_DEBUG(if(_ent && _ent->type != ent_type_id) { \
|
||||
log_fatal("Invalid entity cast from %s to " #typename, ent_type_name(_ent->type)); \
|
||||
}); \
|
||||
CASTPTR_ASSUME_ALIGNED(_ent, typename); \
|
||||
assert(_ent->type == ENT_TYPE_ID(typename)); \
|
||||
UNION_CAST(EntityInterface*, typename*, _ent); \
|
||||
}))
|
||||
#else
|
||||
#define _internal_ENT_CAST(ent, typename, ent_type_id) CASTPTR_ASSUME_ALIGNED(ent, typename)
|
||||
#define ENT_CAST(ent, typename) UNION_CAST(EntityInterface*, typename*, (ent));
|
||||
#endif
|
||||
|
||||
#define ENT_CAST(ent, typename) _internal_ENT_CAST(ent, typename, ENT_TYPE_ID(typename))
|
||||
#define ENT_CAST_CUSTOM(ent, typename) _internal_ENT_CAST(ent, typename, _ENT_TYPEID_CustomEntity)
|
||||
|
||||
void ent_init(void);
|
||||
void ent_shutdown(void);
|
||||
void ent_register(EntityInterface *ent, EntityType type) attr_nonnull(1);
|
||||
|
@ -165,48 +150,66 @@ void ent_hook_post_draw(EntityDrawHookCallback callback, void *arg);
|
|||
void ent_unhook_post_draw(EntityDrawHookCallback callback);
|
||||
|
||||
struct BoxedEntity {
|
||||
alignas(alignof(void*)) uintptr_t ent; // not an actual pointer to avert the temptation to use it directly.
|
||||
EntityInterface *ent;
|
||||
uint_fast32_t spawn_id;
|
||||
};
|
||||
|
||||
BoxedEntity _ent_box_Entity(EntityInterface *ent);
|
||||
EntityInterface *_ent_unbox_Entity(BoxedEntity box);
|
||||
attr_nonnull_all
|
||||
INLINE BoxedEntity _ent_box_Entity(EntityInterface *ent) {
|
||||
return (BoxedEntity) { .ent = ent, .spawn_id = ent->spawn_id } ;
|
||||
}
|
||||
|
||||
#define ENT_TYPE(typename, id) \
|
||||
INLINE EntityInterface *_ent_unbox_Entity(BoxedEntity box) {
|
||||
EntityInterface *e = box.ent;
|
||||
|
||||
if(e && e->spawn_id == box.spawn_id) {
|
||||
return e;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define ENT_EMIT_BOX_DEFS(typename, ...) \
|
||||
typedef union Boxed##typename { \
|
||||
BoxedEntity as_generic; \
|
||||
struct { \
|
||||
uintptr_t ent; \
|
||||
typename *ent; \
|
||||
uint_fast32_t spawn_id; \
|
||||
}; \
|
||||
} Boxed##typename; \
|
||||
struct typename; \
|
||||
Boxed##typename _ent_box_##typename(struct typename *ent); \
|
||||
struct typename *_ent_unbox_##typename(Boxed##typename box); \
|
||||
INLINE Boxed##typename _ent_boxed_passthrough_helper_##typename(Boxed##typename box) { return box; }
|
||||
attr_nonnull_all INLINE Boxed##typename _ent_box_##typename(typename *ent) { \
|
||||
EntityInterface *generic = UNION_CAST(typename*, EntityInterface*, ent); \
|
||||
assert(generic->type == ENT_TYPE_ID(typename)); \
|
||||
return (Boxed##typename) { .as_generic = _ent_box_Entity(generic) }; \
|
||||
} \
|
||||
INLINE typename *_ent_unbox_##typename(Boxed##typename box) { \
|
||||
EntityInterface *generic = _ent_unbox_Entity(box.as_generic); \
|
||||
if(!generic) { return NULL; } \
|
||||
assert(generic->type == ENT_TYPE_ID(typename)); \
|
||||
return UNION_CAST(EntityInterface*, typename*, generic); \
|
||||
} \
|
||||
INLINE Boxed##typename _ent_boxed_passthrough_helper_##typename(Boxed##typename box) { return box; } \
|
||||
INLINE typename *_ent_unboxed_passthrough_helper_##typename(typename *ent) { return ent; }
|
||||
|
||||
ENT_TYPES
|
||||
#undef ENT_TYPE
|
||||
ENTITIES(ENT_EMIT_BOX_DEFS,)
|
||||
#undef ENT_EMIT_BOX_DEFS
|
||||
|
||||
INLINE BoxedEntity _ent_boxed_passthrough_helper_Entity(BoxedEntity box) { return box; }
|
||||
INLINE EntityInterface *_ent_unboxed_passthrough_helper_Entity(EntityInterface *ent) { return ent; }
|
||||
|
||||
#define ENT_HANDLE_UNBOXED_DISPATCH(typename, func_prefix) \
|
||||
typename*: func_prefix##typename,
|
||||
|
||||
#define ENT_UNBOXED_DISPATCH_TABLE(func_prefix) \
|
||||
struct Projectile*: func_prefix##Projectile, \
|
||||
struct Laser*: func_prefix##Laser, \
|
||||
struct Enemy*: func_prefix##Enemy, \
|
||||
struct Boss*: func_prefix##Boss, \
|
||||
struct Player*: func_prefix##Player, \
|
||||
struct Item*: func_prefix##Item, \
|
||||
EntityInterface*: func_prefix##Entity \
|
||||
ENTITIES(ENT_HANDLE_UNBOXED_DISPATCH, func_prefix) \
|
||||
EntityInterface*: func_prefix##Entity
|
||||
|
||||
#define ENT_HANDLE_BOXED_DISPATCH(typename, func_prefix) \
|
||||
Boxed##typename: func_prefix##typename,
|
||||
|
||||
#define ENT_BOXED_DISPATCH_TABLE(func_prefix) \
|
||||
BoxedProjectile: func_prefix##Projectile, \
|
||||
BoxedLaser: func_prefix##Laser, \
|
||||
BoxedEnemy: func_prefix##Enemy, \
|
||||
BoxedBoss: func_prefix##Boss, \
|
||||
BoxedPlayer: func_prefix##Player, \
|
||||
BoxedItem: func_prefix##Item, \
|
||||
BoxedEntity: func_prefix##Entity \
|
||||
ENTITIES(ENT_HANDLE_BOXED_DISPATCH, func_prefix) \
|
||||
BoxedEntity: func_prefix##Entity
|
||||
|
||||
#define ENT_UNBOXED_DISPATCH_FUNCTION(func_prefix, ...) \
|
||||
_Generic((MACROHAX_FIRST(__VA_ARGS__)), \
|
||||
|
@ -225,11 +228,10 @@ INLINE BoxedEntity _ent_boxed_passthrough_helper_Entity(BoxedEntity box) { retur
|
|||
)(MACROHAX_EXPAND(__VA_ARGS__))
|
||||
|
||||
#define ENT_BOX(ent) ENT_UNBOXED_DISPATCH_FUNCTION(_ent_box_, ent)
|
||||
#define ENT_UNBOX(box) ENT_BOXED_DISPATCH_FUNCTION(_ent_unbox_, box)
|
||||
#define ENT_BOX_OR_PASSTHROUGH(ent) ENT_MIXED_DISPATCH_FUNCTION(_ent_box_, _ent_boxed_passthrough_helper_, ent)
|
||||
|
||||
#define ENT_BOX_CUSTOM(ent) _ent_box_Entity(&(ent)->entity_interface)
|
||||
#define ENT_UNBOX_CUSTOM(box, type) ENT_CAST_CUSTOM(_ent_unbox_Entity(box), type)
|
||||
#define ENT_UNBOX(box) ENT_BOXED_DISPATCH_FUNCTION(_ent_unbox_, box)
|
||||
#define ENT_UNBOX_OR_PASSTHROUGH(ent) ENT_MIXED_DISPATCH_FUNCTION(_ent_unboxed_passthrough_helper_, _ent_unbox_, ent)
|
||||
|
||||
typedef struct BoxedEntityArray {
|
||||
BoxedEntity *array;
|
||||
|
@ -237,7 +239,7 @@ typedef struct BoxedEntityArray {
|
|||
uint size;
|
||||
} BoxedEntityArray;
|
||||
|
||||
#define ENT_TYPE(typename, id) \
|
||||
#define ENT_EMIT_ARRAY_DEFS(typename, ...) \
|
||||
typedef union Boxed##typename##Array { \
|
||||
BoxedEntityArray as_generic_UNSAFE; \
|
||||
struct { \
|
||||
|
@ -251,8 +253,8 @@ typedef struct BoxedEntityArray {
|
|||
a->array[a->size++] = box; \
|
||||
}
|
||||
|
||||
ENT_TYPES
|
||||
#undef ENT_TYPE
|
||||
ENTITIES(ENT_EMIT_ARRAY_DEFS,)
|
||||
#undef ENT_EMIT_ARRAY_DEFS
|
||||
|
||||
INLINE void _ent_array_add_BoxedEntity(BoxedEntity box, BoxedEntityArray *a) {
|
||||
assert(a->size < a->capacity);
|
||||
|
@ -277,22 +279,25 @@ INLINE void _ent_array_add_Entity(struct EntityInterface *ent, BoxedEntityArray
|
|||
#define ENT_ARRAY(_typename, _capacity) \
|
||||
((Boxed##_typename##Array) { .array = (Boxed##_typename[_capacity]) { 0 }, .capacity = (_capacity), .size = 0 })
|
||||
|
||||
#define _ent_array_iterator MACROHAX_ADDLINENUM(_ent_array_iterator)
|
||||
#define _ent_array_temp MACROHAX_ADDLINENUM(_ent_array_temp)
|
||||
|
||||
#define ENT_ARRAY_FOREACH(_array, _var, _block) do { \
|
||||
for(uint MACROHAX_ADDLINENUM(_ent_array_iterator) = 0; MACROHAX_ADDLINENUM(_ent_array_iterator) < (_array)->size; ++MACROHAX_ADDLINENUM(_ent_array_iterator)) { \
|
||||
void *MACROHAX_ADDLINENUM(_ent_array_temp) = ENT_ARRAY_GET((_array), MACROHAX_ADDLINENUM(_ent_array_iterator)); \
|
||||
if(MACROHAX_ADDLINENUM(_ent_array_temp) != NULL) { \
|
||||
_var = MACROHAX_ADDLINENUM(_ent_array_temp); \
|
||||
for(uint _ent_array_iterator = 0; _ent_array_iterator < (_array)->size; ++_ent_array_iterator) { \
|
||||
void *_ent_array_temp = ENT_ARRAY_GET((_array), _ent_array_iterator); \
|
||||
if(_ent_array_temp != NULL) { \
|
||||
_var = _ent_array_temp; \
|
||||
_block \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define ENT_ARRAY_FOREACH_COUNTER(_array, _cntr_var, _ent_var, _block) do { \
|
||||
for(uint MACROHAX_ADDLINENUM(_ent_array_iterator) = 0; MACROHAX_ADDLINENUM(_ent_array_iterator) < (_array)->size; ++MACROHAX_ADDLINENUM(_ent_array_iterator)) { \
|
||||
void *MACROHAX_ADDLINENUM(_ent_array_temp) = ENT_ARRAY_GET((_array), MACROHAX_ADDLINENUM(_ent_array_iterator)); \
|
||||
if(MACROHAX_ADDLINENUM(_ent_array_temp) != NULL) { \
|
||||
_cntr_var = MACROHAX_ADDLINENUM(_ent_array_iterator); \
|
||||
_ent_var = MACROHAX_ADDLINENUM(_ent_array_temp); \
|
||||
for(uint _ent_array_iterator = 0; _ent_array_iterator < (_array)->size; ++_ent_array_iterator) { \
|
||||
void *_ent_array_temp = ENT_ARRAY_GET((_array), _ent_array_iterator); \
|
||||
if(_ent_array_temp != NULL) { \
|
||||
_cntr_var = _ent_array_iterator; \
|
||||
_ent_var = _ent_array_temp; \
|
||||
_block \
|
||||
} \
|
||||
} \
|
||||
|
|
|
@ -125,7 +125,7 @@ Item* create_item(cmplx pos, cmplx v, ItemType type) {
|
|||
|
||||
i->ent.draw_layer = LAYER_ITEM | i->type;
|
||||
i->ent.draw_func = ent_draw_item;
|
||||
ent_register(&i->ent, ENT_ITEM);
|
||||
ent_register(&i->ent, ENT_TYPE_ID(Item));
|
||||
|
||||
return i;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "objectpool.h"
|
||||
#include "entity.h"
|
||||
|
||||
typedef struct Item Item;
|
||||
typedef LIST_ANCHOR(Item) ItemList;
|
||||
|
||||
typedef enum {
|
||||
|
@ -54,9 +53,7 @@ typedef union ItemCounts {
|
|||
int as_array[ITEM_LAST - ITEM_FIRST];
|
||||
} ItemCounts;
|
||||
|
||||
struct Item {
|
||||
ENTITY_INTERFACE_NAMED(Item, ent);
|
||||
|
||||
DEFINE_ENTITY_TYPE(Item, {
|
||||
int birthtime;
|
||||
int collecttime;
|
||||
cmplx pos;
|
||||
|
@ -67,7 +64,7 @@ struct Item {
|
|||
float pickup_value;
|
||||
|
||||
cmplx v;
|
||||
};
|
||||
});
|
||||
|
||||
Item *create_item(cmplx pos, cmplx v, ItemType type);
|
||||
void delete_item(Item *item);
|
||||
|
|
28
src/known_entities.h
Normal file
28
src/known_entities.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#ifndef IGUARD_known_entities_h
|
||||
#define IGUARD_known_entities_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#define ENTITIES_CORE(X, ...) \
|
||||
X(Boss, __VA_ARGS__) \
|
||||
X(Enemy, __VA_ARGS__) \
|
||||
X(Item, __VA_ARGS__) \
|
||||
X(Laser, __VA_ARGS__) \
|
||||
X(Player, __VA_ARGS__) \
|
||||
X(Projectile, __VA_ARGS__) \
|
||||
|
||||
#include "plrmodes/entities.h"
|
||||
|
||||
#define ENTITIES(X, ...) \
|
||||
ENTITIES_CORE(X, __VA_ARGS__) \
|
||||
ENTITIES_PLAYERMODES(X, __VA_ARGS__) \
|
||||
|
||||
#endif // IGUARD_known_entities_h
|
|
@ -169,7 +169,7 @@ Laser *create_laser(cmplx pos, float time, float deathtime, const Color *color,
|
|||
|
||||
l->ent.draw_layer = LAYER_LASER_HIGH;
|
||||
l->ent.draw_func = ent_draw_laser;
|
||||
ent_register(&l->ent, ENT_LASER);
|
||||
ent_register(&l->ent, ENT_TYPE_ID(Laser));
|
||||
|
||||
if(l->lrule)
|
||||
l->lrule(l, EVENT_BIRTH);
|
||||
|
@ -318,7 +318,7 @@ static void lasers_ent_predraw_hook(EntityInterface *ent, void *arg) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(ent && ent->type == ENT_LASER) {
|
||||
if(ent && ent->type == ENT_TYPE_ID(Laser)) {
|
||||
if(lasers.saved_fb != NULL) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -16,15 +16,12 @@
|
|||
#include "resource/shader_program.h"
|
||||
#include "entity.h"
|
||||
|
||||
typedef struct Laser Laser;
|
||||
typedef LIST_ANCHOR(Laser) LaserList;
|
||||
|
||||
typedef cmplx (*LaserPosRule)(Laser* l, float time);
|
||||
typedef void (*LaserLogicRule)(Laser* l, int time);
|
||||
|
||||
struct Laser {
|
||||
ENTITY_INTERFACE_NAMED(Laser, ent);
|
||||
|
||||
DEFINE_ENTITY_TYPE(Laser, {
|
||||
cmplx pos;
|
||||
cmplx args[4];
|
||||
|
||||
|
@ -47,7 +44,7 @@ struct Laser {
|
|||
|
||||
uchar unclearable : 1;
|
||||
uchar collision_active : 1;
|
||||
};
|
||||
});
|
||||
|
||||
#define create_lasercurve1c(p, time, deathtime, clr, rule, a0) create_laser(p, time, deathtime, clr, rule, 0, a0, 0, 0, 0)
|
||||
#define create_lasercurve2c(p, time, deathtime, clr, rule, a0, a1) create_laser(p, time, deathtime, clr, rule, 0, a0, a1, 0, 0)
|
||||
|
|
|
@ -67,7 +67,7 @@ void player_stage_post_init(Player *plr) {
|
|||
plr->ent.draw_layer = LAYER_PLAYER;
|
||||
plr->ent.draw_func = ent_draw_player;
|
||||
plr->ent.damage_func = ent_damage_player;
|
||||
ent_register(&plr->ent, ENT_PLAYER);
|
||||
ent_register(&plr->ent, ENT_TYPE_ID(Player));
|
||||
|
||||
COEVENT_INIT_ARRAY(plr->events);
|
||||
|
||||
|
@ -1623,13 +1623,13 @@ void player_register_damage(Player *plr, EntityInterface *target, const DamageIn
|
|||
|
||||
if(target != NULL) {
|
||||
switch(target->type) {
|
||||
case ENT_ENEMY: {
|
||||
case ENT_TYPE_ID(Enemy): {
|
||||
pos = ENT_CAST(target, Enemy)->pos;
|
||||
player_add_points(&global.plr, damage->amount * 0.5, pos);
|
||||
break;
|
||||
}
|
||||
|
||||
case ENT_BOSS: {
|
||||
case ENT_TYPE_ID(Boss): {
|
||||
pos = ENT_CAST(target, Boss)->pos;
|
||||
player_add_points(&global.plr, damage->amount * 0.2, pos);
|
||||
break;
|
||||
|
@ -1640,7 +1640,7 @@ void player_register_damage(Player *plr, EntityInterface *target, const DamageIn
|
|||
}
|
||||
|
||||
if(!isnan(creal(pos)) && damage->type == DMG_PLAYER_DISCHARGE) {
|
||||
double rate = target->type == ENT_BOSS ? 110 : 256;
|
||||
double rate = target->type == ENT_TYPE_ID(Boss) ? 110 : 256;
|
||||
spawn_and_collect_items(pos, 1, ITEM_VOLTAGE, (int)(damage->amount / rate));
|
||||
}
|
||||
|
||||
|
|
22
src/player.h
22
src/player.h
|
@ -15,6 +15,12 @@
|
|||
#define PLR_DPS_STATS
|
||||
#endif
|
||||
|
||||
#ifdef PLR_DPS_STATS
|
||||
#define IF_PLR_DPS_STATS(...) __VA_ARGS__
|
||||
#else
|
||||
#define IF_PLR_DPS_STATS(...)
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "enemy.h"
|
||||
#include "gamepad.h"
|
||||
|
@ -78,8 +84,6 @@ enum {
|
|||
INFLAGS_MOVE = INFLAG_UP | INFLAG_DOWN | INFLAG_LEFT | INFLAG_RIGHT
|
||||
};
|
||||
|
||||
typedef struct Player Player;
|
||||
|
||||
typedef struct PowerSurgeBonus {
|
||||
uint baseline;
|
||||
uint score;
|
||||
|
@ -89,9 +93,7 @@ typedef struct PowerSurgeBonus {
|
|||
float discharge_damage;
|
||||
} PowerSurgeBonus;
|
||||
|
||||
struct Player {
|
||||
ENTITY_INTERFACE_NAMED(Player, ent);
|
||||
|
||||
DEFINE_ENTITY_TYPE(Player, {
|
||||
cmplx pos;
|
||||
cmplx velocity;
|
||||
cmplx deathpos;
|
||||
|
@ -156,11 +158,11 @@ struct Player {
|
|||
bool gamepadmove;
|
||||
bool iddqd;
|
||||
|
||||
#ifdef PLR_DPS_STATS
|
||||
int dmglogframe;
|
||||
int dmglog[240];
|
||||
#endif
|
||||
};
|
||||
IF_PLR_DPS_STATS(
|
||||
int dmglogframe;
|
||||
int dmglog[240];
|
||||
)
|
||||
});
|
||||
|
||||
// this is used by both player and replay code
|
||||
enum {
|
||||
|
|
31
src/plrmodes/entities.h
Normal file
31
src/plrmodes/entities.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#ifndef IGUARD_plrmodes_entities_h
|
||||
#define IGUARD_plrmodes_entities_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "reimu_a_entities.h"
|
||||
#include "reimu_b_entities.h"
|
||||
|
||||
#include "marisa_a_entities.h"
|
||||
#include "marisa_b_entities.h"
|
||||
|
||||
#include "youmu_a_entities.h"
|
||||
#include "youmu_b_entities.h"
|
||||
|
||||
#define ENTITIES_PLAYERMODES(X, ...) \
|
||||
ENTITIES_ReimuA(X, __VA_ARGS__) \
|
||||
ENTITIES_ReimuB(X, __VA_ARGS__) \
|
||||
ENTITIES_MarisaA(X, __VA_ARGS__) \
|
||||
ENTITIES_MarisaB(X, __VA_ARGS__) \
|
||||
ENTITIES_YoumuA(X, __VA_ARGS__) \
|
||||
ENTITIES_YoumuB(X, __VA_ARGS__) \
|
||||
|
||||
#endif // IGUARD_plrmodes_entities_h
|
|
@ -20,13 +20,9 @@
|
|||
|
||||
#define HAKKERO_RETRACT_TIME 4
|
||||
|
||||
typedef struct MarisaAController MarisaAController;
|
||||
typedef struct MarisaLaser MarisaLaser;
|
||||
typedef struct MarisaSlave MarisaSlave;
|
||||
typedef struct MasterSpark MasterSpark;
|
||||
typedef struct MarisaALaser MarisaALaser;
|
||||
|
||||
struct MarisaSlave {
|
||||
ENTITY_INTERFACE_NAMED(MarisaAController, ent);
|
||||
DEFINE_ENTITY_TYPE(MarisaASlave, {
|
||||
Sprite *sprite;
|
||||
ShaderProgram *shader;
|
||||
cmplx pos;
|
||||
|
@ -34,10 +30,16 @@ struct MarisaSlave {
|
|||
real shot_angle;
|
||||
real flare_alpha;
|
||||
bool alive;
|
||||
};
|
||||
});
|
||||
|
||||
struct MarisaLaser {
|
||||
LIST_INTERFACE(MarisaLaser);
|
||||
DEFINE_ENTITY_TYPE(MarisaAMasterSpark, {
|
||||
cmplx pos;
|
||||
cmplx dir;
|
||||
real alpha;
|
||||
});
|
||||
|
||||
struct MarisaALaser {
|
||||
LIST_INTERFACE(MarisaALaser);
|
||||
cmplx pos;
|
||||
struct {
|
||||
cmplx first;
|
||||
|
@ -46,25 +48,16 @@ struct MarisaLaser {
|
|||
real alpha;
|
||||
};
|
||||
|
||||
struct MasterSpark {
|
||||
ENTITY_INTERFACE_NAMED(MarisaAController, ent);
|
||||
cmplx pos;
|
||||
cmplx dir;
|
||||
real alpha;
|
||||
};
|
||||
|
||||
struct MarisaAController {
|
||||
ENTITY_INTERFACE_NAMED(MarisaAController, laser_renderer);
|
||||
|
||||
DEFINE_ENTITY_TYPE(MarisaAController, {
|
||||
Player *plr;
|
||||
LIST_ANCHOR(MarisaLaser) lasers;
|
||||
LIST_ANCHOR(MarisaALaser) lasers;
|
||||
|
||||
COEVENTS_ARRAY(
|
||||
slaves_expired
|
||||
) events;
|
||||
};
|
||||
});
|
||||
|
||||
static void trace_laser(MarisaLaser *laser, cmplx vel, real damage) {
|
||||
static void trace_laser(MarisaALaser *laser, cmplx vel, real damage) {
|
||||
ProjCollisionResult col;
|
||||
ProjectileList lproj = { .first = NULL };
|
||||
|
||||
|
@ -111,7 +104,7 @@ static void trace_laser(MarisaLaser *laser, cmplx vel, real damage) {
|
|||
.layer = LAYER_PARTICLE_HIGH,
|
||||
);
|
||||
|
||||
if(col.type == PCOL_ENTITY && col.entity->type == ENT_ENEMY) {
|
||||
if(col.type == PCOL_ENTITY && col.entity->type == ENT_TYPE_ID(Enemy)) {
|
||||
assert(num_enemy_collissions < ARRAY_SIZE(enemy_collisions));
|
||||
if(num_enemy_collissions < ARRAY_SIZE(enemy_collisions)) {
|
||||
c = enemy_collisions + num_enemy_collissions++;
|
||||
|
@ -154,7 +147,7 @@ static float set_alpha_dimmed(Uniform *u_alpha, float a) {
|
|||
}
|
||||
|
||||
static void marisa_laser_draw_slave(EntityInterface *ent) {
|
||||
MarisaSlave *slave = ENT_CAST_CUSTOM(ent, MarisaSlave);
|
||||
MarisaASlave *slave = ENT_CAST(ent, MarisaASlave);
|
||||
|
||||
ShaderCustomParams shader_params;
|
||||
shader_params.color = *RGBA(0.2, 0.4, 0.5, slave->flare_alpha * 0.75);
|
||||
|
@ -193,7 +186,7 @@ static void draw_laser_beam(cmplx src, cmplx dst, real size, real step, real t,
|
|||
}
|
||||
|
||||
static void marisa_laser_draw_lasers(EntityInterface *ent) {
|
||||
MarisaAController *ctrl = ENT_CAST_CUSTOM(ent, MarisaAController);
|
||||
MarisaAController *ctrl = ENT_CAST(ent, MarisaAController);
|
||||
real t = global.frames;
|
||||
|
||||
ShaderProgram *shader = r_shader_get("marisa_laser");
|
||||
|
@ -222,7 +215,7 @@ static void marisa_laser_draw_lasers(EntityInterface *ent) {
|
|||
BLENDFACTOR_SRC_COLOR, BLENDFACTOR_ONE, BLENDOP_MAX
|
||||
));
|
||||
|
||||
for(MarisaLaser *laser = ctrl->lasers.first; laser; laser = laser->next) {
|
||||
for(MarisaALaser *laser = ctrl->lasers.first; laser; laser = laser->next) {
|
||||
if(set_alpha(u_alpha, laser->alpha)) {
|
||||
draw_laser_beam(laser->pos, laser->trace_hit.last, 32, 128, -0.02 * t, tex1, u_length);
|
||||
}
|
||||
|
@ -250,7 +243,7 @@ static void marisa_laser_draw_lasers(EntityInterface *ent) {
|
|||
r_uniform_vec4(u_clr0, 0.5, 0.0, 0.0, 0.0);
|
||||
r_uniform_vec4(u_clr1, 1.0, 0.0, 0.0, 0.0);
|
||||
|
||||
for(MarisaLaser *laser = ctrl->lasers.first; laser; laser = laser->next) {
|
||||
for(MarisaALaser *laser = ctrl->lasers.first; laser; laser = laser->next) {
|
||||
if(set_alpha_dimmed(u_alpha, laser->alpha)) {
|
||||
draw_laser_beam(laser->pos, laser->trace_hit.first, 40, 128, t * -0.12, tex0, u_length);
|
||||
}
|
||||
|
@ -259,7 +252,7 @@ static void marisa_laser_draw_lasers(EntityInterface *ent) {
|
|||
r_uniform_vec4(u_clr0, 2.0, 1.0, 2.0, 0.0);
|
||||
r_uniform_vec4(u_clr1, 0.1, 0.1, 1.0, 0.0);
|
||||
|
||||
for(MarisaLaser *laser = ctrl->lasers.first; laser; laser = laser->next) {
|
||||
for(MarisaALaser *laser = ctrl->lasers.first; laser; laser = laser->next) {
|
||||
if(set_alpha_dimmed(u_alpha, laser->alpha)) {
|
||||
draw_laser_beam(laser->pos, laser->trace_hit.first, 42, 200, t * -0.03, tex0, u_length);
|
||||
}
|
||||
|
@ -270,7 +263,7 @@ static void marisa_laser_draw_lasers(EntityInterface *ent) {
|
|||
.shader_ptr = r_shader_get("sprite_default"),
|
||||
};
|
||||
|
||||
for(MarisaLaser *laser = ctrl->lasers.first; laser; laser = laser->next) {
|
||||
for(MarisaALaser *laser = ctrl->lasers.first; laser; laser = laser->next) {
|
||||
float a = laser->alpha * 0.8f;
|
||||
cmplx spread;
|
||||
|
||||
|
@ -297,25 +290,25 @@ static void marisa_laser_flash_draw(Projectile *p, int t, ProjDrawRuleArgs args)
|
|||
r_draw_sprite(&sp);
|
||||
}
|
||||
|
||||
TASK(marisa_laser_slave_expire, { BoxedEntity slave; }) {
|
||||
MarisaSlave *slave = TASK_BIND_CUSTOM(ARGS.slave, MarisaSlave);
|
||||
TASK(marisa_laser_slave_expire, { BoxedMarisaASlave slave; }) {
|
||||
MarisaASlave *slave = TASK_BIND(ARGS.slave);
|
||||
slave->alive = false;
|
||||
}
|
||||
|
||||
static void marisa_laser_show_laser(MarisaAController *ctrl, MarisaLaser *laser) {
|
||||
static void marisa_laser_show_laser(MarisaAController *ctrl, MarisaALaser *laser) {
|
||||
alist_append(&ctrl->lasers, laser);
|
||||
}
|
||||
|
||||
static void marisa_laser_hide_laser(MarisaAController *ctrl, MarisaLaser *laser) {
|
||||
static void marisa_laser_hide_laser(MarisaAController *ctrl, MarisaALaser *laser) {
|
||||
alist_unlink(&ctrl->lasers, laser);
|
||||
}
|
||||
|
||||
TASK(marisa_laser_fader, {
|
||||
MarisaAController *ctrl;
|
||||
const MarisaLaser *ref_laser;
|
||||
const MarisaALaser *ref_laser;
|
||||
}) {
|
||||
MarisaAController *ctrl = ARGS.ctrl;
|
||||
MarisaLaser fader = *ARGS.ref_laser;
|
||||
MarisaALaser fader = *ARGS.ref_laser;
|
||||
|
||||
marisa_laser_show_laser(ctrl, &fader);
|
||||
|
||||
|
@ -327,16 +320,16 @@ TASK(marisa_laser_fader, {
|
|||
marisa_laser_hide_laser(ctrl, &fader);
|
||||
}
|
||||
|
||||
static void marisa_laser_fade_laser(MarisaAController *ctrl, MarisaLaser *laser) {
|
||||
static void marisa_laser_fade_laser(MarisaAController *ctrl, MarisaALaser *laser) {
|
||||
marisa_laser_hide_laser(ctrl, laser);
|
||||
INVOKE_TASK(marisa_laser_fader, ctrl, laser);
|
||||
}
|
||||
|
||||
TASK(marisa_laser_slave_shot_cleanup, {
|
||||
MarisaAController *ctrl;
|
||||
MarisaLaser **active_laser;
|
||||
MarisaALaser **active_laser;
|
||||
}) {
|
||||
MarisaLaser *active_laser = *ARGS.active_laser;
|
||||
MarisaALaser *active_laser = *ARGS.active_laser;
|
||||
if(active_laser) {
|
||||
marisa_laser_fade_laser(ARGS.ctrl, active_laser);
|
||||
}
|
||||
|
@ -344,16 +337,16 @@ TASK(marisa_laser_slave_shot_cleanup, {
|
|||
|
||||
TASK(marisa_laser_slave_shot, {
|
||||
MarisaAController *ctrl;
|
||||
BoxedEntity slave;
|
||||
BoxedMarisaASlave slave;
|
||||
}) {
|
||||
MarisaAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
MarisaSlave *slave = TASK_BIND_CUSTOM(ARGS.slave, MarisaSlave);
|
||||
MarisaASlave *slave = TASK_BIND(ARGS.slave);
|
||||
|
||||
Animation *fire_anim = get_ani("fire");
|
||||
AniSequence *fire_anim_seq = get_ani_sequence(fire_anim, "main");
|
||||
|
||||
MarisaLaser *active_laser = NULL;
|
||||
MarisaALaser *active_laser = NULL;
|
||||
INVOKE_TASK_AFTER(&TASK_EVENTS(THIS_TASK)->finished, marisa_laser_slave_shot_cleanup, ctrl, &active_laser);
|
||||
|
||||
for(;;) {
|
||||
|
@ -362,7 +355,7 @@ TASK(marisa_laser_slave_shot, {
|
|||
|
||||
// We started shooting - register a laser for rendering
|
||||
|
||||
MarisaLaser laser = { 0 };
|
||||
MarisaALaser laser = { 0 };
|
||||
marisa_laser_show_laser(ctrl, &laser);
|
||||
active_laser = &laser;
|
||||
|
||||
|
@ -408,7 +401,7 @@ TASK(marisa_laser_slave, {
|
|||
}) {
|
||||
MarisaAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
MarisaSlave *slave = TASK_HOST_CUSTOM_ENT(MarisaSlave);
|
||||
MarisaASlave *slave = TASK_HOST_ENT(MarisaASlave);
|
||||
slave->alive = true;
|
||||
slave->ent.draw_func = marisa_laser_draw_slave;
|
||||
slave->ent.draw_layer = LAYER_PLAYER_SLAVE;
|
||||
|
@ -416,11 +409,11 @@ TASK(marisa_laser_slave, {
|
|||
slave->shader = r_shader_get("sprite_hakkero");
|
||||
slave->sprite = get_sprite("hakkero");
|
||||
|
||||
INVOKE_TASK_WHEN(&ctrl->events.slaves_expired, marisa_laser_slave_expire, ENT_BOX_CUSTOM(slave));
|
||||
INVOKE_TASK_WHEN(&ctrl->events.slaves_expired, marisa_laser_slave_expire, ENT_BOX(slave));
|
||||
|
||||
BoxedTask shot_task = cotask_box(INVOKE_SUBTASK(marisa_laser_slave_shot,
|
||||
.ctrl = ctrl,
|
||||
.slave = ENT_BOX_CUSTOM(slave)
|
||||
.slave = ENT_BOX(slave)
|
||||
));
|
||||
|
||||
/* unfocused focused */
|
||||
|
@ -476,7 +469,7 @@ static real marisa_laser_masterspark_width(real progress) {
|
|||
}
|
||||
|
||||
static void marisa_laser_draw_masterspark(EntityInterface *ent) {
|
||||
MasterSpark *ms = ENT_CAST_CUSTOM(ent, MasterSpark);
|
||||
MarisaAMasterSpark *ms = ENT_CAST(ent, MarisaAMasterSpark);
|
||||
marisa_common_masterspark_draw(1, &(MarisaBeamInfo) {
|
||||
ms->pos,
|
||||
800 + I * VIEWPORT_H * 1.25,
|
||||
|
@ -485,7 +478,7 @@ static void marisa_laser_draw_masterspark(EntityInterface *ent) {
|
|||
}, ms->alpha);
|
||||
}
|
||||
|
||||
static void marisa_laser_masterspark_damage(MasterSpark *ms) {
|
||||
static void marisa_laser_masterspark_damage(MarisaAMasterSpark *ms) {
|
||||
// lazy inefficient approximation of the beam parabola
|
||||
|
||||
float r = 96 * ms->alpha;
|
||||
|
@ -521,7 +514,7 @@ TASK(marisa_laser_masterspark, { MarisaAController *ctrl; }) {
|
|||
MarisaAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
MasterSpark *ms = TASK_HOST_CUSTOM_ENT(MasterSpark);
|
||||
MarisaAMasterSpark *ms = TASK_HOST_ENT(MarisaAMasterSpark);
|
||||
ms->dir = 1;
|
||||
ms->ent.draw_func = marisa_laser_draw_masterspark;
|
||||
ms->ent.draw_layer = LAYER_PLAYER_FOCUS - 1;
|
||||
|
@ -696,12 +689,12 @@ TASK(marisa_laser_shot_forward, { MarisaAController *ctrl; }) {
|
|||
}
|
||||
|
||||
TASK(marisa_laser_controller, { BoxedPlayer plr; }) {
|
||||
MarisaAController *ctrl = TASK_HOST_CUSTOM_ENT(MarisaAController);
|
||||
MarisaAController *ctrl = TASK_HOST_ENT(MarisaAController);
|
||||
ctrl->plr = TASK_BIND(ARGS.plr);
|
||||
TASK_HOST_EVENTS(ctrl->events);
|
||||
|
||||
ctrl->laser_renderer.draw_func = marisa_laser_draw_lasers;
|
||||
ctrl->laser_renderer.draw_layer = LAYER_PLAYER_FOCUS;
|
||||
ctrl->ent.draw_func = marisa_laser_draw_lasers;
|
||||
ctrl->ent.draw_layer = LAYER_PLAYER_FOCUS;
|
||||
|
||||
INVOKE_SUBTASK(marisa_laser_power_handler, ctrl);
|
||||
INVOKE_SUBTASK(marisa_laser_bomb_handler, ctrl);
|
||||
|
|
19
src/plrmodes/marisa_a_entities.h
Normal file
19
src/plrmodes/marisa_a_entities.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#ifndef IGUARD_plrmodes_marisa_a_entities_h
|
||||
#define IGUARD_plrmodes_marisa_a_entities_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#define ENTITIES_MarisaA(X, ...) \
|
||||
X(MarisaAController, __VA_ARGS__) \
|
||||
X(MarisaAMasterSpark, __VA_ARGS__) \
|
||||
X(MarisaASlave, __VA_ARGS__) \
|
||||
|
||||
#endif // IGUARD_plrmodes_marisa_a_entities_h
|
16
src/plrmodes/marisa_b_entities.h
Normal file
16
src/plrmodes/marisa_b_entities.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#ifndef IGUARD_plrmodes_marisa_b_entities_h
|
||||
#define IGUARD_plrmodes_marisa_b_entities_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#define ENTITIES_MarisaB(X, ...) \
|
||||
|
||||
#endif // IGUARD_plrmodes_marisa_b_entities_h
|
|
@ -32,15 +32,13 @@ typedef struct ReimuAController {
|
|||
) events;
|
||||
} ReimuAController;
|
||||
|
||||
typedef struct ReimuSlave ReimuSlave;
|
||||
struct ReimuSlave {
|
||||
ENTITY_INTERFACE_NAMED(ReimuSlave, ent);
|
||||
DEFINE_ENTITY_TYPE(ReimuASlave, {
|
||||
Sprite *sprite;
|
||||
ShaderProgram *shader;
|
||||
cmplx pos;
|
||||
Color color;
|
||||
uint alive;
|
||||
};
|
||||
});
|
||||
|
||||
static void reimu_spirit_preload(void) {
|
||||
const int flags = RESF_DEFAULT;
|
||||
|
@ -72,7 +70,7 @@ static void reimu_spirit_preload(void) {
|
|||
}
|
||||
|
||||
TASK(reimu_spirit_needle, { cmplx pos; cmplx vel; real damage; ShaderProgram *shader; }) {
|
||||
Projectile *p = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_needle,
|
||||
.pos = ARGS.pos,
|
||||
.color = RGBA(0.5, 0.5, 0.5, 0.5),
|
||||
|
@ -131,7 +129,7 @@ static Projectile *reimu_spirit_spawn_ofuda_particle(Projectile *p, int t, real
|
|||
TASK(reimu_spirit_homing_impact, { BoxedProjectile p; }) {
|
||||
Projectile *ref = NOT_NULL(ENT_UNBOX(ARGS.p));
|
||||
|
||||
Projectile *p = TASK_BIND_UNBOXED(PARTICLE(
|
||||
Projectile *p = TASK_BIND(PARTICLE(
|
||||
.proto = ref->proto,
|
||||
.color = &ref->color,
|
||||
.timeout = 32,
|
||||
|
@ -159,7 +157,7 @@ static inline real reimu_spirit_homing_aimfactor(real t, real maxt) {
|
|||
}
|
||||
|
||||
TASK(reimu_spirit_homing, { cmplx pos; cmplx vel; real damage; ShaderProgram *shader; }) {
|
||||
Projectile *p = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_ofuda,
|
||||
.pos = ARGS.pos,
|
||||
.color = RGBA(0.7, 0.63, 0.665, 0.7),
|
||||
|
@ -329,7 +327,7 @@ TASK(reimu_spirit_bomb_orb, { BoxedPlayer plr; int index; real angle; }) {
|
|||
int index = ARGS.index;
|
||||
|
||||
Player *plr = ENT_UNBOX(ARGS.plr);
|
||||
Projectile *orb = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *orb = TASK_BIND(PROJECTILE(
|
||||
.pos = plr->pos,
|
||||
.timeout = 200 + 20 * index,
|
||||
.type = PROJ_PLAYER,
|
||||
|
@ -442,7 +440,7 @@ TASK(reimu_spirit_bomb_handler, { ReimuAController *ctrl; }) {
|
|||
}
|
||||
|
||||
TASK(reimu_spirit_ofuda, { cmplx pos; cmplx vel; real damage; ShaderProgram *shader; }) {
|
||||
Projectile *ofuda = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *ofuda = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_ofuda,
|
||||
.pos = ARGS.pos,
|
||||
.color = RGBA_MUL_ALPHA(1, 1, 1, 0.5),
|
||||
|
@ -459,7 +457,7 @@ TASK(reimu_spirit_ofuda, { cmplx pos; cmplx vel; real damage; ShaderProgram *sha
|
|||
}
|
||||
|
||||
static void reimu_spirit_draw_slave(EntityInterface *ent) {
|
||||
ReimuSlave *slave = ENT_CAST_CUSTOM(ent, ReimuSlave);
|
||||
ReimuASlave *slave = ENT_CAST(ent, ReimuASlave);
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.color = &slave->color,
|
||||
.pos.as_cmplx = slave->pos,
|
||||
|
@ -469,11 +467,9 @@ static void reimu_spirit_draw_slave(EntityInterface *ent) {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
static ReimuSlave *reimu_spirit_create_slave(ReimuAController *ctrl, const Color *color) {
|
||||
static ReimuASlave *reimu_spirit_create_slave(ReimuAController *ctrl, const Color *color) {
|
||||
Player *plr = ctrl->plr;
|
||||
ReimuSlave *slave = TASK_HOST_CUSTOM_ENT(ReimuSlave);
|
||||
ReimuASlave *slave = TASK_HOST_ENT(ReimuASlave);
|
||||
slave->sprite = get_sprite("yinyang");
|
||||
slave->shader = r_shader_get("sprite_yinyang");
|
||||
slave->pos = plr->pos;
|
||||
|
@ -491,14 +487,14 @@ static ReimuSlave *reimu_spirit_create_slave(ReimuAController *ctrl, const Color
|
|||
}
|
||||
|
||||
TASK(reimu_slave_shot_particles, {
|
||||
BoxedEntity slave;
|
||||
BoxedReimuASlave slave;
|
||||
int num;
|
||||
cmplx dir;
|
||||
Color *color0;
|
||||
Color *color1;
|
||||
Sprite *sprite;
|
||||
}) {
|
||||
ReimuSlave *slave = TASK_BIND_CUSTOM(ARGS.slave, ReimuSlave);
|
||||
ReimuASlave *slave = TASK_BIND(ARGS.slave);
|
||||
Color color0 = *ARGS.color0;
|
||||
Color color1 = *ARGS.color1;
|
||||
int num = ARGS.num;
|
||||
|
@ -527,10 +523,10 @@ TASK(reimu_slave_shot_particles, {
|
|||
|
||||
TASK(reimu_spirit_slave_needle_shot, {
|
||||
ReimuAController *ctrl;
|
||||
BoxedEntity e;
|
||||
BoxedReimuASlave slave;
|
||||
}) {
|
||||
Player *plr = ARGS.ctrl->plr;
|
||||
ReimuSlave *slave = TASK_BIND_CUSTOM(ARGS.e, ReimuSlave);
|
||||
ReimuASlave *slave = TASK_BIND(ARGS.slave);
|
||||
|
||||
ShaderProgram *shader = r_shader_get("sprite_particle");
|
||||
Sprite *particle_spr = get_sprite("part/stain");
|
||||
|
@ -542,7 +538,7 @@ TASK(reimu_spirit_slave_needle_shot, {
|
|||
WAIT_EVENT_OR_DIE(&plr->events.shoot);
|
||||
|
||||
INVOKE_SUBTASK(reimu_slave_shot_particles,
|
||||
.slave = ENT_BOX_CUSTOM(slave),
|
||||
.slave = ENT_BOX(slave),
|
||||
.color0 = RGBA(0.5, 0, 0, 0),
|
||||
.color1 = RGBA(0.5, 0.25, 0, 0),
|
||||
.num = delay,
|
||||
|
@ -569,9 +565,9 @@ TASK(reimu_spirit_slave_needle, {
|
|||
}) {
|
||||
ReimuAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
ReimuSlave *slave = reimu_spirit_create_slave(ctrl, RGB(1.0, 0.8, 0.8));
|
||||
ReimuASlave *slave = reimu_spirit_create_slave(ctrl, RGB(1.0, 0.8, 0.8));
|
||||
|
||||
INVOKE_SUBTASK(reimu_spirit_slave_needle_shot, ctrl, ENT_BOX_CUSTOM(slave));
|
||||
INVOKE_SUBTASK(reimu_spirit_slave_needle_shot, ctrl, ENT_BOX(slave));
|
||||
|
||||
real dist = ARGS.distance;
|
||||
cmplx offset = dist * cdir(ARGS.rotation_offset);
|
||||
|
@ -593,11 +589,11 @@ TASK(reimu_spirit_slave_needle, {
|
|||
|
||||
TASK(reimu_spirit_slave_homing_shot, {
|
||||
ReimuAController *ctrl;
|
||||
BoxedEntity slave;
|
||||
BoxedReimuASlave slave;
|
||||
cmplx vel;
|
||||
}) {
|
||||
Player *plr = ARGS.ctrl->plr;
|
||||
ReimuSlave *slave = TASK_BIND_CUSTOM(ARGS.slave, ReimuSlave);
|
||||
ReimuASlave *slave = TASK_BIND(ARGS.slave);
|
||||
|
||||
ShaderProgram *shader = r_shader_get("sprite_particle");
|
||||
Sprite *particle_spr = get_sprite("part/stain");
|
||||
|
@ -611,7 +607,7 @@ TASK(reimu_spirit_slave_homing_shot, {
|
|||
WAIT_EVENT_OR_DIE(&plr->events.shoot);
|
||||
|
||||
INVOKE_SUBTASK(reimu_slave_shot_particles,
|
||||
.slave = ENT_BOX_CUSTOM(slave),
|
||||
.slave = ENT_BOX(slave),
|
||||
.color0 = RGBA(0.5, 0.125, 0, 0),
|
||||
.color1 = RGBA(0.5, 0.125, 0.25, 0),
|
||||
.num = delay,
|
||||
|
@ -637,9 +633,9 @@ TASK(reimu_spirit_slave_homing, {
|
|||
}) {
|
||||
ReimuAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
ReimuSlave *slave = reimu_spirit_create_slave(ctrl, RGB(0.95, 0.75, 1.0));
|
||||
ReimuASlave *slave = reimu_spirit_create_slave(ctrl, RGB(0.95, 0.75, 1.0));
|
||||
|
||||
INVOKE_SUBTASK(reimu_spirit_slave_homing_shot, ctrl, ENT_BOX_CUSTOM(slave), ARGS.shot_vel);
|
||||
INVOKE_SUBTASK(reimu_spirit_slave_homing_shot, ctrl, ENT_BOX(slave), ARGS.shot_vel);
|
||||
|
||||
cmplx offset = ARGS.offset;
|
||||
real target_speed = 0.005 * cabs(offset);
|
||||
|
|
17
src/plrmodes/reimu_a_entities.h
Normal file
17
src/plrmodes/reimu_a_entities.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#ifndef IGUARD_plrmodes_reimu_a_entities_h
|
||||
#define IGUARD_plrmodes_reimu_a_entities_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#define ENTITIES_ReimuA(X, ...) \
|
||||
X(ReimuASlave, __VA_ARGS__) \
|
||||
|
||||
#endif // IGUARD_plrmodes_reimu_a_entities_h
|