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
|
|
@ -42,35 +42,31 @@
|
|||
|
||||
#define NUM_GAPS 4
|
||||
|
||||
typedef struct ReimuGap ReimuGap;
|
||||
typedef struct ReimuSlave ReimuSlave;
|
||||
typedef struct ReimuBController ReimuBController;
|
||||
typedef struct ReimuBGap ReimuBGap;
|
||||
|
||||
struct ReimuGap {
|
||||
ReimuGap *link; // bullets entering this gap will exit from the linked gap
|
||||
struct ReimuBGap {
|
||||
ReimuBGap *link; // bullets entering this gap will exit from the linked gap
|
||||
cmplx pos; // position of the gap's center in viewport space
|
||||
cmplx orientation; // normalized, points to the side the gap is 'attached' to
|
||||
cmplx parallel_axis; // normalized, parallel the gap, perpendicular to orientation
|
||||
};
|
||||
|
||||
struct ReimuSlave {
|
||||
ENTITY_INTERFACE_NAMED(ReimuSlave, ent);
|
||||
DEFINE_ENTITY_TYPE(ReimuBSlave, {
|
||||
Sprite *sprite;
|
||||
ShaderProgram *shader;
|
||||
cmplx pos;
|
||||
uint alive;
|
||||
};
|
||||
});
|
||||
|
||||
struct ReimuBController {
|
||||
ENTITY_INTERFACE_NAMED(ReimuBController, gap_renderer);
|
||||
DEFINE_ENTITY_TYPE(ReimuBController, {
|
||||
Player *plr;
|
||||
ShaderProgram *yinyang_shader;
|
||||
Sprite *yinyang_sprite;
|
||||
|
||||
union {
|
||||
ReimuGap array[NUM_GAPS];
|
||||
ReimuBGap array[NUM_GAPS];
|
||||
struct {
|
||||
ReimuGap left, top, right, bottom;
|
||||
ReimuBGap left, top, right, bottom;
|
||||
};
|
||||
} gaps;
|
||||
|
||||
|
@ -79,7 +75,7 @@ struct ReimuBController {
|
|||
) events;
|
||||
|
||||
real bomb_alpha;
|
||||
};
|
||||
});
|
||||
|
||||
static void reimu_dream_gap_bomb_projectile_draw(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
SpriteParamsBuffer spbuf;
|
||||
|
@ -116,7 +112,7 @@ TASK(reimu_dream_gap_bomb_projectile, {
|
|||
Sprite *sprite;
|
||||
Sprite *impact_sprite;
|
||||
}) {
|
||||
Projectile *p = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.angle = rng_angle(),
|
||||
.color = ARGS.color,
|
||||
.damage = 75,
|
||||
|
@ -165,7 +161,7 @@ TASK(reimu_dream_bomb_barrage, { ReimuBController *ctrl; }) {
|
|||
Color *pcolor = HSLA(t/30.0, 0.5, 0.5, 0.5);
|
||||
|
||||
for(int i = 0; i < NUM_GAPS; ++i) {
|
||||
ReimuGap *gap = ctrl->gaps.array + i;
|
||||
ReimuBGap *gap = ctrl->gaps.array + i;
|
||||
INVOKE_TASK(reimu_dream_gap_bomb_projectile,
|
||||
.pos = gap->pos + gap->parallel_axis * GAP_LENGTH * 0.25 * rng_sreal(),
|
||||
.vel = -20 * gap->orientation,
|
||||
|
@ -216,7 +212,7 @@ static void reimu_dream_draw_gap_lights(ReimuBController *ctrl, int time, real s
|
|||
real len = GAP_LENGTH * 3 * sqrt(log1p(strength + 1) / 0.693f);
|
||||
|
||||
for(int i = 0; i < NUM_GAPS; ++i) {
|
||||
ReimuGap *gap = ctrl->gaps.array + i;
|
||||
ReimuBGap *gap = ctrl->gaps.array + i;
|
||||
cmplx center = gap->pos - gap->orientation * (len * 0.5 - GAP_WIDTH * 0.6);
|
||||
|
||||
r_mat_mv_push();
|
||||
|
@ -229,14 +225,14 @@ static void reimu_dream_draw_gap_lights(ReimuBController *ctrl, int time, real s
|
|||
}
|
||||
|
||||
static void reimu_dream_draw_gaps(EntityInterface *gap_renderer_ent) {
|
||||
ReimuBController *ctrl = ENT_CAST_CUSTOM(gap_renderer_ent, ReimuBController);
|
||||
ReimuBController *ctrl = ENT_CAST(gap_renderer_ent, ReimuBController);
|
||||
|
||||
float gaps[NUM_GAPS][2];
|
||||
float angles[NUM_GAPS];
|
||||
int links[NUM_GAPS];
|
||||
|
||||
for(int i = 0; i < NUM_GAPS; ++i) {
|
||||
ReimuGap *gap = ctrl->gaps.array + i;
|
||||
ReimuBGap *gap = ctrl->gaps.array + i;
|
||||
gaps[i][0] = creal(gap->pos);
|
||||
gaps[i][1] = cimag(gap->pos);
|
||||
angles[i] = -carg(gap->orientation);
|
||||
|
@ -284,7 +280,7 @@ static void reimu_dream_draw_gaps(EntityInterface *gap_renderer_ent) {
|
|||
};
|
||||
|
||||
for(int i = 0; i < NUM_GAPS; ++i) {
|
||||
ReimuGap *gap = ctrl->gaps.array + i;
|
||||
ReimuBGap *gap = ctrl->gaps.array + i;
|
||||
yinyang.pos.as_cmplx = gap->pos + gap->parallel_axis * -0.5 * GAP_LENGTH;
|
||||
r_draw_sprite(&yinyang);
|
||||
yinyang.pos.as_cmplx = gap->pos + gap->parallel_axis * +0.5 * GAP_LENGTH;
|
||||
|
@ -327,7 +323,7 @@ static void reimu_dream_bullet_warp(ReimuBController *ctrl, Projectile *p, int *
|
|||
Rect p_bbox = { p->pos - p_long_side * half, p->pos + p_long_side * half };
|
||||
|
||||
for(int i = 0; i < NUM_GAPS; ++i) {
|
||||
ReimuGap *gap = ctrl->gaps.array + i;
|
||||
ReimuBGap *gap = ctrl->gaps.array + i;
|
||||
real a = (carg(-gap->orientation) - carg(p->move.velocity));
|
||||
|
||||
if(fabs(a) < M_TAU/3) {
|
||||
|
@ -351,7 +347,7 @@ static void reimu_dream_bullet_warp(ReimuBController *ctrl, Projectile *p, int *
|
|||
fract = 1 - cimag(o - gap_bbox.top_left) / cimag(gap_size);
|
||||
}
|
||||
|
||||
ReimuGap *ngap = gap->link;
|
||||
ReimuBGap *ngap = gap->link;
|
||||
o = ngap->pos + ngap->parallel_axis * GAP_LENGTH * (1 - fract - 0.5);
|
||||
|
||||
reimu_dream_spawn_warp_effect(gap->pos + gap->parallel_axis * GAP_LENGTH * (fract - 0.5), false);
|
||||
|
@ -370,7 +366,7 @@ static void reimu_dream_bullet_warp(ReimuBController *ctrl, Projectile *p, int *
|
|||
}
|
||||
|
||||
static void reimu_dream_draw_slave(EntityInterface *ent) {
|
||||
ReimuSlave *slave = ENT_CAST_CUSTOM(ent, ReimuSlave);
|
||||
ReimuBSlave *slave = ENT_CAST(ent, ReimuBSlave);
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite_ptr = slave->sprite,
|
||||
.shader_ptr = slave->shader,
|
||||
|
@ -388,7 +384,7 @@ TASK(reimu_dream_needle, {
|
|||
ShaderProgram *shader;
|
||||
}) {
|
||||
ReimuBController *ctrl = ARGS.ctrl;
|
||||
Projectile *p = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_needle2,
|
||||
.pos = ARGS.pos,
|
||||
.color = RGBA_MUL_ALPHA(1, 1, 1, 0.35),
|
||||
|
@ -421,12 +417,12 @@ TASK(reimu_dream_needle, {
|
|||
|
||||
TASK(reimu_dream_slave_shot, {
|
||||
ReimuBController *ctrl;
|
||||
BoxedEntity slave;
|
||||
BoxedReimuBSlave slave;
|
||||
cmplx vel;
|
||||
}) {
|
||||
ReimuBController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
ReimuSlave *slave = TASK_BIND_CUSTOM(ARGS.slave, ReimuSlave);
|
||||
ReimuBSlave *slave = TASK_BIND(ARGS.slave);
|
||||
cmplx vel = ARGS.vel;
|
||||
ShaderProgram *shader = r_shader_get("sprite_particle");
|
||||
|
||||
|
@ -451,7 +447,7 @@ TASK(reimu_dream_slave, {
|
|||
}) {
|
||||
ReimuBController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
ReimuSlave *slave = TASK_HOST_CUSTOM_ENT(ReimuSlave);
|
||||
ReimuBSlave *slave = TASK_HOST_ENT(ReimuBSlave);
|
||||
slave->ent.draw_layer = LAYER_PLAYER_SLAVE;
|
||||
slave->ent.draw_func = reimu_dream_draw_slave;
|
||||
slave->sprite = get_sprite("yinyang"),
|
||||
|
@ -469,7 +465,7 @@ TASK(reimu_dream_slave, {
|
|||
|
||||
INVOKE_SUBTASK(reimu_dream_slave_shot,
|
||||
.ctrl = ctrl,
|
||||
.slave = ENT_BOX_CUSTOM(slave),
|
||||
.slave = ENT_BOX(slave),
|
||||
.vel = 20 * ARGS.shot_dir
|
||||
);
|
||||
|
||||
|
@ -523,7 +519,7 @@ TASK(reimu_dream_process_gaps, { ReimuBController *ctrl; }) {
|
|||
cmplx ofs_factors = 1 + I;
|
||||
|
||||
for(int i = 0; i < NUM_GAPS; ++i) {
|
||||
ReimuGap *gap = ctrl->gaps.array + i;
|
||||
ReimuBGap *gap = ctrl->gaps.array + i;
|
||||
gap->pos = reimu_dream_gap_pos(vp, ref_pos, gap->orientation, gap->parallel_axis, ofs_factors);
|
||||
gap->pos += (2 * GAP_WIDTH + GAP_OFFSET) * gap->orientation;
|
||||
}
|
||||
|
@ -537,7 +533,7 @@ TASK(reimu_dream_process_gaps, { ReimuBController *ctrl; }) {
|
|||
ofs_factors = 1 + I * !is_focused; // no extra clamping of vertical gaps if focused
|
||||
|
||||
for(int i = 0; i < NUM_GAPS; ++i) {
|
||||
ReimuGap *gap = ctrl->gaps.array + i;
|
||||
ReimuBGap *gap = ctrl->gaps.array + i;
|
||||
cmplx target_pos = reimu_dream_gap_pos(vp, ref_pos, gap->orientation, gap->parallel_axis, ofs_factors);
|
||||
capproach_asymptotic_p(&gap->pos, target_pos, pos_approach_rate, 1e-5);
|
||||
}
|
||||
|
@ -546,7 +542,7 @@ TASK(reimu_dream_process_gaps, { ReimuBController *ctrl; }) {
|
|||
|
||||
TASK(reimu_dream_ofuda, { ReimuBController *ctrl; cmplx pos; cmplx vel; ShaderProgram *shader; }) {
|
||||
ReimuBController *ctrl = ARGS.ctrl;
|
||||
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),
|
||||
|
@ -626,39 +622,36 @@ TASK(reimu_dream_controller_tick, { ReimuBController *ctrl; }) {
|
|||
}
|
||||
|
||||
TASK(reimu_dream_controller, { BoxedPlayer plr; }) {
|
||||
ReimuBController ctrl = { 0 };
|
||||
ctrl.plr = TASK_BIND(ARGS.plr);
|
||||
COEVENT_INIT_ARRAY(ctrl.events);
|
||||
ReimuBController *ctrl = TASK_HOST_ENT(ReimuBController);
|
||||
ctrl->plr = TASK_BIND(ARGS.plr);
|
||||
TASK_HOST_EVENTS(ctrl->events);
|
||||
|
||||
ctrl.yinyang_shader = r_shader_get("sprite_yinyang");
|
||||
ctrl.yinyang_sprite = get_sprite("yinyang");
|
||||
ctrl->yinyang_shader = r_shader_get("sprite_yinyang");
|
||||
ctrl->yinyang_sprite = get_sprite("yinyang");
|
||||
|
||||
ctrl.gap_renderer.draw_func = reimu_dream_draw_gaps;
|
||||
ctrl.gap_renderer.draw_layer = LAYER_PLAYER_FOCUS;
|
||||
ent_register(&ctrl.gap_renderer, ENT_CUSTOM);
|
||||
ctrl->ent.draw_func = reimu_dream_draw_gaps;
|
||||
ctrl->ent.draw_layer = LAYER_PLAYER_FOCUS;
|
||||
|
||||
ctrl.gaps.left.link = &ctrl.gaps.top;
|
||||
ctrl.gaps.top.link = &ctrl.gaps.left;
|
||||
ctrl.gaps.right.link = &ctrl.gaps.bottom;
|
||||
ctrl.gaps.bottom.link = &ctrl.gaps.right;
|
||||
ctrl->gaps.left.link = &ctrl->gaps.top;
|
||||
ctrl->gaps.top.link = &ctrl->gaps.left;
|
||||
ctrl->gaps.right.link = &ctrl->gaps.bottom;
|
||||
ctrl->gaps.bottom.link = &ctrl->gaps.right;
|
||||
|
||||
ctrl.gaps.left.orientation = -1;
|
||||
ctrl.gaps.right.orientation = 1;
|
||||
ctrl.gaps.top.orientation = -I;
|
||||
ctrl.gaps.bottom.orientation = I;
|
||||
ctrl->gaps.left.orientation = -1;
|
||||
ctrl->gaps.right.orientation = 1;
|
||||
ctrl->gaps.top.orientation = -I;
|
||||
ctrl->gaps.bottom.orientation = I;
|
||||
|
||||
ctrl.gaps.left.parallel_axis = ctrl.gaps.right.parallel_axis = I;
|
||||
ctrl.gaps.top.parallel_axis = ctrl.gaps.bottom.parallel_axis = 1;
|
||||
ctrl->gaps.left.parallel_axis = ctrl->gaps.right.parallel_axis = I;
|
||||
ctrl->gaps.top.parallel_axis = ctrl->gaps.bottom.parallel_axis = 1;
|
||||
|
||||
INVOKE_SUBTASK(reimu_dream_controller_tick, &ctrl);
|
||||
INVOKE_SUBTASK(reimu_dream_process_gaps, &ctrl);
|
||||
INVOKE_SUBTASK(reimu_dream_shot_forward, &ctrl);
|
||||
INVOKE_SUBTASK(reimu_dream_power_handler, &ctrl);
|
||||
INVOKE_SUBTASK(reimu_dream_bomb_handler, &ctrl);
|
||||
INVOKE_SUBTASK(reimu_dream_controller_tick, ctrl);
|
||||
INVOKE_SUBTASK(reimu_dream_process_gaps, ctrl);
|
||||
INVOKE_SUBTASK(reimu_dream_shot_forward, ctrl);
|
||||
INVOKE_SUBTASK(reimu_dream_power_handler, ctrl);
|
||||
INVOKE_SUBTASK(reimu_dream_bomb_handler, ctrl);
|
||||
|
||||
WAIT_EVENT(&TASK_EVENTS(THIS_TASK)->finished);
|
||||
COEVENT_CANCEL_ARRAY(ctrl.events);
|
||||
ent_unregister(&ctrl.gap_renderer);
|
||||
STALL;
|
||||
}
|
||||
|
||||
static void reimu_dream_init(Player *plr) {
|
||||
|
|
18
src/plrmodes/reimu_b_entities.h
Normal file
18
src/plrmodes/reimu_b_entities.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* 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_b_entities_h
|
||||
#define IGUARD_plrmodes_reimu_b_entities_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#define ENTITIES_ReimuB(X, ...) \
|
||||
X(ReimuBController, __VA_ARGS__) \
|
||||
X(ReimuBSlave, __VA_ARGS__) \
|
||||
|
||||
#endif // IGUARD_plrmodes_reimu_b_entities_h
|
|
@ -21,9 +21,9 @@
|
|||
#define SHOT_MYON_DAMAGE 30
|
||||
|
||||
typedef struct YoumuAController YoumuAController;
|
||||
typedef struct YoumuMyon YoumuMyon;
|
||||
typedef struct YoumuAMyon YoumuAMyon;
|
||||
|
||||
struct YoumuMyon {
|
||||
struct YoumuAMyon {
|
||||
struct {
|
||||
Sprite *trail;
|
||||
Sprite *smoke;
|
||||
|
@ -44,7 +44,7 @@ struct YoumuAController {
|
|||
} sprites;
|
||||
|
||||
Player *plr;
|
||||
YoumuMyon myon;
|
||||
YoumuAMyon myon;
|
||||
};
|
||||
|
||||
static Color *myon_color(Color *c, float f, float opacity, float alpha) {
|
||||
|
@ -53,7 +53,7 @@ static Color *myon_color(Color *c, float f, float opacity, float alpha) {
|
|||
return c;
|
||||
}
|
||||
|
||||
static cmplx myon_tail_dir(YoumuMyon *myon) {
|
||||
static cmplx myon_tail_dir(YoumuAMyon *myon) {
|
||||
cmplx dir = myon->dir * cdir(0.1 * sin(global.frames * 0.05));
|
||||
real f = myon->focus_factor;
|
||||
return f * f * dir;
|
||||
|
@ -83,10 +83,10 @@ static ProjDrawRule myon_draw_trail(float focus_factor, float opacity) {
|
|||
};
|
||||
}
|
||||
|
||||
TASK(youmu_mirror_myon_trail, { YoumuMyon *myon; cmplx pos; }) {
|
||||
YoumuMyon *myon = ARGS.myon;
|
||||
TASK(youmu_mirror_myon_trail, { YoumuAMyon *myon; cmplx pos; }) {
|
||||
YoumuAMyon *myon = ARGS.myon;
|
||||
|
||||
Projectile *p = TASK_BIND_UNBOXED(PARTICLE(
|
||||
Projectile *p = TASK_BIND(PARTICLE(
|
||||
.angle = rng_angle(),
|
||||
.draw_rule = pdraw_timeout_scale(2, 0.01),
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE | PFLAG_MANUALANGLE | PFLAG_PLRSPECIALPARTICLE,
|
||||
|
@ -108,7 +108,7 @@ TASK(youmu_mirror_myon_trail, { YoumuMyon *myon; cmplx pos; }) {
|
|||
}
|
||||
}
|
||||
|
||||
static void myon_spawn_trail(YoumuMyon *myon, int t) {
|
||||
static void myon_spawn_trail(YoumuAMyon *myon, int t) {
|
||||
cmplx pos = myon->pos + 3 * cdir(global.frames * 0.07);
|
||||
cmplx stardust_v = 3 * myon_tail_dir(myon) * cdir(M_PI/16*sin(1.33*t));
|
||||
real f = myon->focus_factor;
|
||||
|
@ -160,7 +160,7 @@ static void myon_draw_proj_trail(Projectile *p, int t, ProjDrawRuleArgs args) {
|
|||
}
|
||||
|
||||
TASK(youmu_mirror_myon_proj, { cmplx pos; cmplx vel; real dmg; const Color *clr; ShaderProgram *shader; }) {
|
||||
Projectile *p = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.color = ARGS.clr,
|
||||
.damage = ARGS.dmg,
|
||||
.layer = LAYER_PLAYER_SHOT | 0x10,
|
||||
|
@ -229,7 +229,7 @@ static void myon_proj_color(Color *clr, real focus_factor) {
|
|||
|
||||
TASK(youmu_mirror_myon_shot, { YoumuAController *ctrl; }) {
|
||||
YoumuAController *ctrl = ARGS.ctrl;
|
||||
YoumuMyon *myon = &ctrl->myon;
|
||||
YoumuAMyon *myon = &ctrl->myon;
|
||||
Player *plr = ctrl->plr;
|
||||
ShaderProgram *shader = r_shader_get("sprite_youmu_myon_shot");
|
||||
|
||||
|
@ -287,7 +287,7 @@ TASK(youmu_mirror_myon_shot, { YoumuAController *ctrl; }) {
|
|||
|
||||
TASK(youmu_mirror_myon, { YoumuAController *ctrl; }) {
|
||||
YoumuAController *ctrl = ARGS.ctrl;
|
||||
YoumuMyon *myon = &ctrl->myon;
|
||||
YoumuAMyon *myon = &ctrl->myon;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
myon->sprites.trail = get_sprite("part/myon");
|
||||
|
@ -455,7 +455,7 @@ static void youmu_mirror_draw_speed_trail(Projectile *p, int t, ProjDrawRuleArgs
|
|||
|
||||
TASK(youmu_mirror_bomb_controller, { YoumuAController *ctrl; }) {
|
||||
YoumuAController *ctrl = ARGS.ctrl;
|
||||
YoumuMyon *myon = &ctrl->myon;
|
||||
YoumuAMyon *myon = &ctrl->myon;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
cmplx vel = -30 * myon->dir;
|
||||
|
@ -506,7 +506,7 @@ TASK(youmu_mirror_bomb_controller, { YoumuAController *ctrl; }) {
|
|||
TASK(youmu_mirror_bomb_postprocess, { YoumuAController *ctrl; }) {
|
||||
YoumuAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
YoumuMyon *myon = &ctrl->myon;
|
||||
YoumuAMyon *myon = &ctrl->myon;
|
||||
CoEvent *pp_event = &stage_get_draw_events()->postprocess_before_overlay;
|
||||
|
||||
ShaderProgram *shader = r_shader_get("youmua_bomb");
|
||||
|
|
16
src/plrmodes/youmu_a_entities.h
Normal file
16
src/plrmodes/youmu_a_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_youmu_a_entities_h
|
||||
#define IGUARD_plrmodes_youmu_a_entities_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#define ENTITIES_YoumuA(X, ...) \
|
||||
|
||||
#endif // IGUARD_plrmodes_youmu_a_entities_h
|
|
@ -208,7 +208,7 @@ static void youmu_haunting_power_shot(Player *plr, int p) {
|
|||
}
|
||||
|
||||
TASK(youmu_homing_shot, { BoxedPlayer plr; }) {
|
||||
Projectile *p = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_hghost,
|
||||
.pos = ENT_UNBOX(ARGS.plr)->pos,
|
||||
.color = RGB(0.75, 0.9, 1),
|
||||
|
@ -263,7 +263,7 @@ TASK(youmu_orb_homing_spirit, { cmplx pos; cmplx velocity; cmplx target; real ch
|
|||
return;
|
||||
}
|
||||
|
||||
Projectile *p = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_hghost,
|
||||
.pos = ARGS.pos,
|
||||
.color = color_mul_scalar(RGB(0.75, 0.9, 1), 0.5),
|
||||
|
@ -414,7 +414,7 @@ TASK(youmu_orb_shot, { BoxedPlayer plr; }) {
|
|||
Player *plr = ENT_UNBOX(ARGS.plr);
|
||||
int pwr = plr->power / 100;
|
||||
|
||||
Projectile *orb = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *orb = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_youhoming,
|
||||
.pos = plr->pos,
|
||||
.color = RGB(1, 1, 1),
|
||||
|
|
16
src/plrmodes/youmu_b_entities.h
Normal file
16
src/plrmodes/youmu_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_youmu_b_entities_h
|
||||
#define IGUARD_plrmodes_youmu_b_entities_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#define ENTITIES_YoumuB(X, ...) \
|
||||
|
||||
#endif // IGUARD_plrmodes_youmu_b_entities_h
|
|
@ -295,7 +295,7 @@ static Projectile* _create_projectile(ProjArgs *args) {
|
|||
projectile_set_layer(p, args->layer);
|
||||
|
||||
COEVENT_INIT_ARRAY(p->events);
|
||||
ent_register(&p->ent, ENT_PROJECTILE);
|
||||
ent_register(&p->ent, ENT_TYPE_ID(Projectile));
|
||||
|
||||
// TODO: Maybe allow ACTION_DESTROY here?
|
||||
// But in that case, code that uses this function's return value must be careful to not dereference a NULL pointer.
|
||||
|
|
|
@ -25,11 +25,16 @@
|
|||
#define PROJ_DEBUG
|
||||
#endif
|
||||
|
||||
#ifdef PROJ_DEBUG
|
||||
#define IF_PROJ_DEBUG(...) __VA_ARGS__
|
||||
#else
|
||||
#define IF_PROJ_DEBUG(...)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
RULE_ARGC = 4
|
||||
};
|
||||
|
||||
typedef struct Projectile Projectile;
|
||||
typedef LIST_ANCHOR(Projectile) ProjectileList;
|
||||
typedef LIST_INTERFACE(Projectile) ProjectileListInterface;
|
||||
|
||||
|
@ -84,9 +89,7 @@ typedef enum ProjFlags {
|
|||
// FIXME: prototype stuff awkwardly shoved in this header because of dependency cycles.
|
||||
typedef struct ProjPrototype ProjPrototype;
|
||||
|
||||
struct Projectile {
|
||||
ENTITY_INTERFACE_NAMED(Projectile, ent);
|
||||
|
||||
DEFINE_ENTITY_TYPE(Projectile, {
|
||||
cmplx pos;
|
||||
cmplx pos0;
|
||||
cmplx prevpos; // used to lerp trajectory for collision detection; set this to pos if you intend to "teleport" the projectile in the rule!
|
||||
|
@ -127,10 +130,10 @@ struct Projectile {
|
|||
int graze_cooldown;
|
||||
short graze_counter;
|
||||
|
||||
#ifdef PROJ_DEBUG
|
||||
DebugInfo debug;
|
||||
#endif
|
||||
};
|
||||
IF_PROJ_DEBUG(
|
||||
DebugInfo debug;
|
||||
)
|
||||
});
|
||||
|
||||
typedef struct ProjArgs {
|
||||
ProjPrototype *proto;
|
||||
|
|
|
@ -572,12 +572,12 @@ static bool proximity_predicate(EntityInterface *ent, void *varg) {
|
|||
Circle *area = varg;
|
||||
|
||||
switch(ent->type) {
|
||||
case ENT_PROJECTILE: {
|
||||
case ENT_TYPE_ID(Projectile): {
|
||||
Projectile *p = ENT_CAST(ent, Projectile);
|
||||
return cabs(p->pos - area->origin) < area->radius;
|
||||
}
|
||||
|
||||
case ENT_LASER: {
|
||||
case ENT_TYPE_ID(Laser): {
|
||||
Laser *l = ENT_CAST(ent, Laser);
|
||||
return laser_intersects_circle(l, *area);
|
||||
}
|
||||
|
@ -590,12 +590,12 @@ static bool ellipse_predicate(EntityInterface *ent, void *varg) {
|
|||
Ellipse *e = varg;
|
||||
|
||||
switch(ent->type) {
|
||||
case ENT_PROJECTILE: {
|
||||
case ENT_TYPE_ID(Projectile): {
|
||||
Projectile *p = ENT_CAST(ent, Projectile);
|
||||
return point_in_ellipse(p->pos, *e);
|
||||
}
|
||||
|
||||
case ENT_LASER: {
|
||||
case ENT_TYPE_ID(Laser): {
|
||||
Laser *l = ENT_CAST(ent, Laser);
|
||||
return laser_intersects_ellipse(l, *e);
|
||||
}
|
||||
|
|
|
@ -595,13 +595,13 @@ static bool powersurge_draw_predicate(EntityInterface *ent) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if(ent->type == ENT_PROJECTILE) {
|
||||
if(ent->type == ENT_TYPE_ID(Projectile)) {
|
||||
Projectile *p = ENT_CAST(ent, Projectile);
|
||||
return p->flags & PFLAG_PLRSPECIALPARTICLE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ent->type == ENT_ITEM) {
|
||||
if(ent->type == ENT_TYPE_ID(Item)) {
|
||||
Item *i = ENT_CAST(ent, Item);
|
||||
return i->type == ITEM_VOLTAGE;
|
||||
}
|
||||
|
@ -841,7 +841,7 @@ bool stage_should_draw_particle(Projectile *p) {
|
|||
}
|
||||
|
||||
static bool stage_draw_predicate(EntityInterface *ent) {
|
||||
if(ent->type == ENT_PROJECTILE) {
|
||||
if(ent->type == ENT_TYPE_ID(Projectile)) {
|
||||
Projectile *p = ENT_CAST(ent, Projectile);
|
||||
|
||||
if(p->type == PROJ_PARTICLE) {
|
||||
|
|
|
@ -79,7 +79,7 @@ TASK(wait_event_test, { BoxedEnemy e; int rounds; int delay; int cnt; int cnt_in
|
|||
TASK(test_enemy, {
|
||||
double hp; cmplx pos; cmplx dir;
|
||||
}) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(ARGS.pos, ARGS.hp, BigFairy, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(ARGS.pos, ARGS.hp, BigFairy, NULL, 0));
|
||||
|
||||
INVOKE_TASK_WHEN(&e->events.killed, common_drop_items, &e->pos, {
|
||||
.life_fragment = 1,
|
||||
|
@ -150,7 +150,7 @@ TASK(subtask_test_init, NO_ARGS) {
|
|||
}
|
||||
|
||||
TASK(punching_bag, NO_ARGS) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(0.5*(VIEWPORT_W+VIEWPORT_H*I), 1000, BigFairy, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(0.5*(VIEWPORT_W+VIEWPORT_H*I), 1000, BigFairy, NULL, 0));
|
||||
|
||||
INVOKE_TASK_WHEN(&e->events.killed, common_drop_items, &e->pos, {
|
||||
.life_fragment = 10,
|
||||
|
|
|
@ -66,7 +66,7 @@ TASK(glider_bullet, {
|
|||
TASK(glider_fairy, {
|
||||
double hp; cmplx pos; cmplx dir;
|
||||
}) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(VIEWPORT_W/2-10*I, ARGS.hp, BigFairy, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(VIEWPORT_W/2-10*I, ARGS.hp, BigFairy, NULL, 0));
|
||||
|
||||
INVOKE_TASK_WHEN(&e->events.killed, common_drop_items, &e->pos, {
|
||||
.power = 3,
|
||||
|
|
|
@ -91,8 +91,8 @@ static bool stage1_draw_predicate(EntityInterface *ent) {
|
|||
}
|
||||
|
||||
switch(ent->type) {
|
||||
case ENT_BOSS: return true;
|
||||
case ENT_ENEMY: {
|
||||
case ENT_TYPE_ID(Boss): return true;
|
||||
case ENT_TYPE_ID(Enemy): {
|
||||
Enemy *e = ENT_CAST(ent, Enemy);
|
||||
|
||||
if(e->hp == ENEMY_BOMB) {
|
||||
|
@ -101,7 +101,7 @@ static bool stage1_draw_predicate(EntityInterface *ent) {
|
|||
|
||||
return true;
|
||||
}
|
||||
case ENT_PROJECTILE: {
|
||||
case ENT_TYPE_ID(Projectile): {
|
||||
Projectile *p = ENT_CAST(ent, Projectile);
|
||||
|
||||
if(p->type == PROJ_PARTICLE) {
|
||||
|
|
|
@ -424,7 +424,7 @@ TASK(halation_orb, {
|
|||
cmplx pos[4];
|
||||
int activation_time;
|
||||
}) {
|
||||
Projectile *orb = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *orb = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_plainball,
|
||||
.pos = ARGS.pos[0],
|
||||
.max_viewport_dist = 200,
|
||||
|
@ -567,7 +567,7 @@ DEFINE_EXTERN_TASK(stage1_spell_snow_halation) {
|
|||
}
|
||||
|
||||
TASK(cirno_icicle, { cmplx pos; cmplx vel; }) {
|
||||
Projectile *p = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_crystal,
|
||||
.pos = ARGS.pos,
|
||||
.color = RGB(0.3, 0.3, 0.9),
|
||||
|
@ -649,7 +649,7 @@ TASK(cirno_frostbolt_trail, { BoxedProjectile proj; }) {
|
|||
}
|
||||
|
||||
TASK(cirno_frostbolt, { cmplx pos; cmplx vel; }) {
|
||||
Projectile *p = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_wave,
|
||||
.pos = ARGS.pos,
|
||||
.color = RGBA(0.2, 0.2, 0.4, 0.0),
|
||||
|
@ -756,7 +756,7 @@ void cirno_benchmark(Boss* b, int t) {
|
|||
}
|
||||
|
||||
TASK(burst_fairy, { cmplx pos; cmplx dir; }) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(ARGS.pos, 700, Fairy, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(ARGS.pos, 700, Fairy, NULL, 0));
|
||||
|
||||
INVOKE_TASK_WHEN(&e->events.killed, common_drop_items, &e->pos, {
|
||||
.points = 1,
|
||||
|
@ -840,7 +840,7 @@ TASK(circletoss_shoot_toss, { BoxedEnemy e; int times; int duration; int period;
|
|||
}
|
||||
|
||||
TASK(circletoss_fairy, { cmplx pos; cmplx velocity; cmplx exit_accel; int exit_time; }) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(ARGS.pos, 1500, BigFairy, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(ARGS.pos, 1500, BigFairy, NULL, 0));
|
||||
|
||||
e->move = move_linear(ARGS.velocity);
|
||||
|
||||
|
@ -880,7 +880,7 @@ TASK(sinepass_swirl_move, { BoxedEnemy e; cmplx v; cmplx sv; }) {
|
|||
}
|
||||
|
||||
TASK(sinepass_swirl, { cmplx pos; cmplx vel; cmplx svel; }) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(ARGS.pos, 100, Swirl, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(ARGS.pos, 100, Swirl, NULL, 0));
|
||||
|
||||
INVOKE_TASK_WHEN(&e->events.killed, common_drop_items, &e->pos, {
|
||||
.points = 1,
|
||||
|
@ -910,7 +910,7 @@ TASK(sinepass_swirl, { cmplx pos; cmplx vel; cmplx svel; }) {
|
|||
}
|
||||
|
||||
TASK(circle_fairy, { cmplx pos; cmplx target_pos; }) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(ARGS.pos, 1400, BigFairy, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(ARGS.pos, 1400, BigFairy, NULL, 0));
|
||||
|
||||
INVOKE_TASK_WHEN(&e->events.killed, common_drop_items, &e->pos, {
|
||||
.points = 3,
|
||||
|
@ -959,7 +959,7 @@ TASK(circle_fairy, { cmplx pos; cmplx target_pos; }) {
|
|||
}
|
||||
|
||||
TASK(drop_swirl, { cmplx pos; cmplx vel; cmplx accel; }) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(ARGS.pos, 100, Swirl, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(ARGS.pos, 100, Swirl, NULL, 0));
|
||||
|
||||
INVOKE_TASK_WHEN(&e->events.killed, common_drop_items, &e->pos, {
|
||||
.points = 2,
|
||||
|
@ -988,7 +988,7 @@ TASK(drop_swirl, { cmplx pos; cmplx vel; cmplx accel; }) {
|
|||
}
|
||||
|
||||
TASK(multiburst_fairy, { cmplx pos; cmplx target_pos; cmplx exit_accel; }) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(ARGS.pos, 1000, Fairy, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(ARGS.pos, 1000, Fairy, NULL, 0));
|
||||
|
||||
INVOKE_TASK_WHEN(&e->events.killed, common_drop_items, &e->pos, {
|
||||
.points = 3,
|
||||
|
@ -1046,7 +1046,7 @@ TASK(instantcircle_fairy_shoot, { BoxedEnemy e; int cnt; double speed; double bo
|
|||
}
|
||||
|
||||
TASK(instantcircle_fairy, { cmplx pos; cmplx target_pos; cmplx exit_accel; }) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(ARGS.pos, 1200, Fairy, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(ARGS.pos, 1200, Fairy, NULL, 0));
|
||||
|
||||
INVOKE_TASK_WHEN(&e->events.killed, common_drop_items, &e->pos, {
|
||||
.points = 2,
|
||||
|
@ -1094,7 +1094,7 @@ TASK(waveshot, { cmplx pos; real angle; real spread; real freq; int shots; int i
|
|||
}
|
||||
|
||||
TASK(waveshot_fairy, { cmplx pos; cmplx target_pos; cmplx exit_accel; }) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(ARGS.pos, 4200, BigFairy, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(ARGS.pos, 4200, BigFairy, NULL, 0));
|
||||
|
||||
INVOKE_TASK_WHEN(&e->events.killed, common_drop_items, &e->pos, {
|
||||
.points = 4,
|
||||
|
@ -1125,7 +1125,7 @@ TASK(waveshot_fairy, { cmplx pos; cmplx target_pos; cmplx exit_accel; }) {
|
|||
}
|
||||
|
||||
TASK(explosion_fairy, { cmplx pos; cmplx target_pos; cmplx exit_accel; }) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(ARGS.pos, 6000, BigFairy, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(ARGS.pos, 6000, BigFairy, NULL, 0));
|
||||
|
||||
INVOKE_TASK_WHEN(&e->events.killed, common_drop_items, &e->pos, {
|
||||
.points = 8,
|
||||
|
@ -1579,7 +1579,7 @@ TASK(spawn_midboss, NO_ARGS) {
|
|||
}
|
||||
|
||||
TASK(tritoss_fairy, { cmplx pos; cmplx velocity; cmplx end_velocity; }) {
|
||||
Enemy *e = TASK_BIND_UNBOXED(create_enemy1c(ARGS.pos, 16000, BigFairy, NULL, 0));
|
||||
Enemy *e = TASK_BIND(create_enemy1c(ARGS.pos, 16000, BigFairy, NULL, 0));
|
||||
|
||||
INVOKE_TASK_WHEN(&e->events.killed, common_drop_items, &e->pos, {
|
||||
.points = 5,
|
||||
|
|
|
@ -297,6 +297,10 @@ typedef cmplx64 cmplx;
|
|||
#define ASSUME_ALIGNED(expr, alignment) (expr)
|
||||
#endif
|
||||
|
||||
#define UNION_CAST(_from_type, _to_type, _expr) \
|
||||
((union { _from_type f; _to_type t; }) { .f = (_expr) }).t
|
||||
|
||||
// #define CASTPTR_ASSUME_ALIGNED(expr, type) UNION_CAST(void*, type*, ASSUME_ALIGNED(expr, alignof(type)))
|
||||
#define CASTPTR_ASSUME_ALIGNED(expr, type) ((type*)ASSUME_ALIGNED((expr), alignof(type)))
|
||||
|
||||
#ifdef USE_GNU_EXTENSIONS
|
||||
|
|
Loading…
Reference in a new issue