use "anchored" lists for most game objects
these have a pointer to the last element, thus appending is fast
This commit is contained in:
parent
1c588f1a41
commit
83a8961df6
33 changed files with 522 additions and 214 deletions
|
@ -22,13 +22,13 @@ void aniplayer_create(AniPlayer *plr, Animation *ani, const char *startsequence)
|
|||
}
|
||||
|
||||
Sprite *aniplayer_get_frame(AniPlayer *plr) {
|
||||
assert(plr->queue != NULL);
|
||||
return animation_get_frame(plr->ani, plr->queue->sequence, plr->queue->clock);
|
||||
assert(plr->queue.first != NULL);
|
||||
return animation_get_frame(plr->ani, plr->queue.first->sequence, plr->queue.first->clock);
|
||||
}
|
||||
|
||||
void aniplayer_free(AniPlayer *plr) {
|
||||
plr->queuesize = 0;
|
||||
list_free_all(&plr->queue);
|
||||
alist_free_all(&plr->queue);
|
||||
}
|
||||
|
||||
// Deletes the queue. If hard is set, even the last element is removed leaving the player in an invalid state.
|
||||
|
@ -36,18 +36,19 @@ static void aniplayer_reset(AniPlayer *plr, bool hard) {
|
|||
if(plr->queuesize == 0)
|
||||
return;
|
||||
if(hard) {
|
||||
list_free_all(&plr->queue);
|
||||
alist_free_all(&plr->queue);
|
||||
plr->queuesize = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
list_free_all(&plr->queue->next);
|
||||
list_free_all(&plr->queue.first->next);
|
||||
plr->queue.last = plr->queue.first;
|
||||
plr->queuesize = 1;
|
||||
}
|
||||
|
||||
AniQueueEntry *aniplayer_queue(AniPlayer *plr, const char *seqname, int loops) {
|
||||
AniQueueEntry *s = calloc(1, sizeof(AniQueueEntry));
|
||||
list_append(&plr->queue, s);
|
||||
alist_append(&plr->queue, s);
|
||||
plr->queuesize++;
|
||||
|
||||
if(loops < 0)
|
||||
|
@ -76,13 +77,13 @@ AniQueueEntry *aniplayer_hard_switch(AniPlayer *plr, const char *seqname, int lo
|
|||
}
|
||||
|
||||
void aniplayer_update(AniPlayer *plr) {
|
||||
assert(plr->queue); // The queue should never be empty.
|
||||
AniQueueEntry *s = plr->queue;
|
||||
assert(plr->queue.first != NULL); // The queue should never be empty.
|
||||
AniQueueEntry *s = plr->queue.first;
|
||||
|
||||
s->clock++;
|
||||
// The last condition assures that animations only switch at their end points
|
||||
if(s->clock >= s->duration && plr->queuesize > 1 && s->clock%s->sequence->length == 0) {
|
||||
free(list_pop(&plr->queue));
|
||||
free(alist_pop(&plr->queue));
|
||||
plr->queuesize--;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ typedef struct AniPlayer AniPlayer;
|
|||
struct AniPlayer{
|
||||
Animation *ani;
|
||||
|
||||
AniQueueEntry *queue;
|
||||
LIST_ANCHOR(AniQueueEntry) queue;
|
||||
int queuesize;
|
||||
};
|
||||
|
||||
|
|
27
src/enemy.c
27
src/enemy.c
|
@ -33,14 +33,14 @@ Enemy* _enemy_attach_dbginfo(Enemy *e, DebugInfo *dbg) {
|
|||
|
||||
static void ent_draw_enemy(EntityInterface *ent);
|
||||
|
||||
Enemy *create_enemy_p(Enemy **enemies, complex pos, int hp, EnemyVisualRule visual_rule, EnemyLogicRule logic_rule,
|
||||
Enemy *create_enemy_p(EnemyList *enemies, complex pos, int hp, EnemyVisualRule visual_rule, EnemyLogicRule logic_rule,
|
||||
complex a1, complex a2, complex a3, complex a4) {
|
||||
if(IN_DRAW_CODE) {
|
||||
log_fatal("Tried to spawn an enemy while in drawing code");
|
||||
}
|
||||
|
||||
// XXX: some code relies on the insertion logic
|
||||
Enemy *e = (Enemy*)list_insert(enemies, objpool_acquire(stage_object_pools.enemies));
|
||||
Enemy *e = (Enemy*)alist_insert(enemies, enemies->first, objpool_acquire(stage_object_pools.enemies));
|
||||
e->moving = false;
|
||||
e->dir = 0;
|
||||
|
||||
|
@ -67,7 +67,7 @@ Enemy *create_enemy_p(Enemy **enemies, complex pos, int hp, EnemyVisualRule visu
|
|||
return e;
|
||||
}
|
||||
|
||||
void* _delete_enemy(List **enemies, List* enemy, void *arg) {
|
||||
void* _delete_enemy(ListAnchor *enemies, List* enemy, void *arg) {
|
||||
Enemy *e = (Enemy*)enemy;
|
||||
|
||||
if(e->hp <= 0 && e->hp > ENEMY_IMMUNE) {
|
||||
|
@ -94,17 +94,17 @@ void* _delete_enemy(List **enemies, List* enemy, void *arg) {
|
|||
e->logic_rule(e, EVENT_DEATH);
|
||||
del_ref(enemy);
|
||||
ent_unregister(&e->ent);
|
||||
objpool_release(stage_object_pools.enemies, (ObjectInterface*)list_unlink(enemies, enemy));
|
||||
objpool_release(stage_object_pools.enemies, (ObjectInterface*)alist_unlink(enemies, enemy));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void delete_enemy(Enemy **enemies, Enemy* enemy) {
|
||||
_delete_enemy((List**)enemies, (List*)enemy, NULL);
|
||||
void delete_enemy(EnemyList *enemies, Enemy* enemy) {
|
||||
_delete_enemy((ListAnchor*)enemies, (List*)enemy, NULL);
|
||||
}
|
||||
|
||||
void delete_enemies(Enemy **enemies) {
|
||||
list_foreach(enemies, _delete_enemy, NULL);
|
||||
void delete_enemies(EnemyList *enemies) {
|
||||
alist_foreach(enemies, _delete_enemy, NULL);
|
||||
}
|
||||
|
||||
static void ent_draw_enemy(EntityInterface *ent) {
|
||||
|
@ -133,11 +133,10 @@ static void ent_draw_enemy(EntityInterface *ent) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void killall(Enemy *enemies) {
|
||||
Enemy *e;
|
||||
|
||||
for(e = enemies; e; e = e->next)
|
||||
void killall(EnemyList *enemies) {
|
||||
for(Enemy *e = enemies->first; e; e = e->next) {
|
||||
e->hp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int enemy_flare(Projectile *p, int t) { // a[0] velocity, a[1] ref to enemy
|
||||
|
@ -242,8 +241,8 @@ void Swirl(Enemy *e, int t, bool render) {
|
|||
});
|
||||
}
|
||||
|
||||
void process_enemies(Enemy **enemies) {
|
||||
Enemy *enemy = *enemies, *del = NULL;
|
||||
void process_enemies(EnemyList *enemies) {
|
||||
Enemy *enemy = enemies->first, *del = NULL;
|
||||
|
||||
while(enemy != NULL) {
|
||||
int action = enemy->logic_rule(enemy, global.frames - enemy->birthtime);
|
||||
|
|
11
src/enemy.h
11
src/enemy.h
|
@ -19,6 +19,7 @@
|
|||
#endif
|
||||
|
||||
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);
|
||||
|
||||
|
@ -57,7 +58,7 @@ struct Enemy {
|
|||
#define create_enemy1c(p,h,d,l,a1) create_enemy_p(&global.enemies,p,h,d,l,a1,0,0,0)
|
||||
|
||||
Enemy *create_enemy_p(
|
||||
Enemy **enemies, complex pos, int hp, EnemyVisualRule draw_rule, EnemyLogicRule logic_rule,
|
||||
EnemyList *enemies, complex pos, int hp, EnemyVisualRule draw_rule, EnemyLogicRule logic_rule,
|
||||
complex a1, complex a2, complex a3, complex a4
|
||||
);
|
||||
|
||||
|
@ -66,12 +67,12 @@ Enemy *create_enemy_p(
|
|||
#define create_enemy_p(...) _enemy_attach_dbginfo(create_enemy_p(__VA_ARGS__), _DEBUG_INFO_PTR_)
|
||||
#endif
|
||||
|
||||
void delete_enemy(Enemy **enemies, Enemy* enemy);
|
||||
void delete_enemies(Enemy **enemies);
|
||||
void delete_enemy(EnemyList *enemies, Enemy* enemy);
|
||||
void delete_enemies(EnemyList *enemies);
|
||||
|
||||
void process_enemies(Enemy **enemies);
|
||||
void process_enemies(EnemyList *enemies);
|
||||
|
||||
void killall(Enemy *enemies);
|
||||
void killall(EnemyList *enemies);
|
||||
|
||||
void Fairy(Enemy*, int t, bool render);
|
||||
void Swirl(Enemy*, int t, bool render);
|
||||
|
|
69
src/events.c
69
src/events.c
|
@ -14,8 +14,15 @@
|
|||
#include "video.h"
|
||||
#include "gamepad.h"
|
||||
|
||||
typedef struct EventHandlerContainer {
|
||||
LIST_INTERFACE(struct EventHandlerContainer);
|
||||
EventHandler *handler;
|
||||
} EventHandlerContainer;
|
||||
|
||||
typedef LIST_ANCHOR(EventHandlerContainer) EventHandlerList;
|
||||
|
||||
static hrtime_t keyrepeat_paused_until;
|
||||
static ListContainer *global_handlers;
|
||||
static EventHandlerList global_handlers;
|
||||
|
||||
uint32_t sdl_first_user_event;
|
||||
|
||||
|
@ -49,7 +56,7 @@ void events_shutdown(void) {
|
|||
events_unregister_default_handlers();
|
||||
|
||||
#ifdef DEBUG
|
||||
if(global_handlers) {
|
||||
if(global_handlers.first) {
|
||||
log_warn(
|
||||
"Someone didn't unregister their handler. "
|
||||
"Clean up after yourself, I'm not your personal maid. "
|
||||
|
@ -72,7 +79,7 @@ static bool events_invoke_handler(SDL_Event *event, EventHandler *handler) {
|
|||
}
|
||||
|
||||
static int handler_container_prio_func(List *h) {
|
||||
return ((EventHandler*)((ListContainer*)h)->data)->priority;
|
||||
return ((EventHandlerContainer*)h)->handler->priority;
|
||||
}
|
||||
|
||||
static EventPriority real_priority(EventPriority prio) {
|
||||
|
@ -84,7 +91,13 @@ static EventPriority real_priority(EventPriority prio) {
|
|||
return prio;
|
||||
}
|
||||
|
||||
static bool events_invoke_handlers(SDL_Event *event, ListContainer *h_list, EventHandler *h_array) {
|
||||
static EventHandlerContainer* ehandler_wrap_container(EventHandler *handler) {
|
||||
EventHandlerContainer *c = calloc(1, sizeof(ListContainer));
|
||||
c->handler = handler;
|
||||
return c;
|
||||
}
|
||||
|
||||
static bool events_invoke_handlers(SDL_Event *event, EventHandlerContainer *h_list, EventHandler *h_array) {
|
||||
// invoke handlers from two sources (a list and an array) in the correct order according to priority
|
||||
// list items take precedence
|
||||
//
|
||||
|
@ -97,8 +110,8 @@ static bool events_invoke_handlers(SDL_Event *event, ListContainer *h_list, Even
|
|||
if(h_list && !h_array) {
|
||||
// case 1 (simplest): we have a list and no custom handlers
|
||||
|
||||
for(ListContainer *c = h_list; c; c = c->next) {
|
||||
if((result = events_invoke_handler(event, (EventHandler*)c->data))) {
|
||||
for(EventHandlerContainer *c = h_list; c; c = c->next) {
|
||||
if((result = events_invoke_handler(event, c->handler))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -110,44 +123,31 @@ static bool events_invoke_handlers(SDL_Event *event, ListContainer *h_list, Even
|
|||
// case 2 (suboptimal): we have both a list and a disordered array; need to do some actual work
|
||||
// if you want to optimize this be my guest
|
||||
|
||||
ListContainer *merged_list = NULL;
|
||||
ListContainer *prevc = NULL;
|
||||
EventHandlerList merged_list = { .first = NULL };
|
||||
|
||||
// copy the list
|
||||
for(ListContainer *c = h_list; c; c = c->next) {
|
||||
ListContainer *newc = calloc(1, sizeof(ListContainer));
|
||||
newc->data = c->data;
|
||||
newc->prev = prevc;
|
||||
|
||||
if(prevc) {
|
||||
prevc->next = newc;
|
||||
}
|
||||
|
||||
if(!merged_list) {
|
||||
merged_list = newc;
|
||||
}
|
||||
|
||||
prevc = newc;
|
||||
for(EventHandlerContainer *c = h_list; c; c = c->next) {
|
||||
alist_append(&merged_list, ehandler_wrap_container(c->handler));
|
||||
}
|
||||
|
||||
// merge the array into the list copy, respecting priority
|
||||
for(EventHandler *h = h_array; h->proc; ++h) {
|
||||
list_insert_at_priority_tail(
|
||||
alist_insert_at_priority_tail(
|
||||
&merged_list,
|
||||
list_wrap_container(h),
|
||||
ehandler_wrap_container(h),
|
||||
real_priority(h->priority),
|
||||
handler_container_prio_func
|
||||
);
|
||||
}
|
||||
|
||||
// iterate over the merged list
|
||||
for(ListContainer *c = merged_list; c; c = c->next) {
|
||||
if((result = events_invoke_handler(event, (EventHandler*)c->data))) {
|
||||
for(EventHandlerContainer *c = merged_list.first; c; c = c->next) {
|
||||
if((result = events_invoke_handler(event, c->handler))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
list_free_all(&merged_list);
|
||||
alist_free_all(&merged_list);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -177,9 +177,9 @@ void events_register_handler(EventHandler *handler) {
|
|||
}
|
||||
|
||||
assert(handler_alloc->priority > EPRIO_DEFAULT);
|
||||
list_insert_at_priority_tail(
|
||||
alist_insert_at_priority_tail(
|
||||
&global_handlers,
|
||||
list_wrap_container(handler_alloc),
|
||||
ehandler_wrap_container(handler_alloc),
|
||||
handler_alloc->priority,
|
||||
handler_container_prio_func
|
||||
);
|
||||
|
@ -188,14 +188,13 @@ void events_register_handler(EventHandler *handler) {
|
|||
}
|
||||
|
||||
void events_unregister_handler(EventHandlerProc proc) {
|
||||
ListContainer *next;
|
||||
for(ListContainer *c = global_handlers; c; c = next) {
|
||||
EventHandler *h = c->data;
|
||||
for(EventHandlerContainer *c = global_handlers.first, *next; c; c = next) {
|
||||
EventHandler *h = c->handler;
|
||||
next = c->next;
|
||||
|
||||
if(h->proc == proc) {
|
||||
free(c->data);
|
||||
free(list_unlink(&global_handlers, c));
|
||||
free(c->handler);
|
||||
free(alist_unlink(&global_handlers, c));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -229,7 +228,7 @@ void events_poll(EventHandler *handlers, EventFlags flags) {
|
|||
events_emit(TE_FRAME, 0, NULL, NULL);
|
||||
|
||||
while(SDL_PollEvent(&event)) {
|
||||
events_invoke_handlers(&event, global_handlers, handlers);
|
||||
events_invoke_handlers(&event, global_handlers.first, handlers);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
11
src/global.h
11
src/global.h
|
@ -87,12 +87,11 @@ typedef struct {
|
|||
int8_t diff; // this holds values of type Difficulty, but should be signed to prevent obscure overflow errors
|
||||
Player plr;
|
||||
|
||||
Projectile *projs;
|
||||
Enemy *enemies;
|
||||
Item *items;
|
||||
Laser *lasers;
|
||||
|
||||
Projectile *particles;
|
||||
ProjectileList projs;
|
||||
ProjectileList particles;
|
||||
EnemyList enemies;
|
||||
ItemList items;
|
||||
LaserList lasers;
|
||||
|
||||
int frames; // stage global timer
|
||||
int timer; // stage event timer (freezes on bosses, dialogs, etc.)
|
||||
|
|
|
@ -56,7 +56,7 @@ Item* create_item(complex pos, complex v, ItemType type) {
|
|||
// type = 1 + floor(Life * frand());
|
||||
|
||||
Item *i = (Item*)objpool_acquire(stage_object_pools.items);
|
||||
list_append(&global.items, i);
|
||||
alist_append(&global.items, i);
|
||||
|
||||
i->pos = pos;
|
||||
i->pos0 = pos;
|
||||
|
@ -74,7 +74,7 @@ Item* create_item(complex pos, complex v, ItemType type) {
|
|||
|
||||
void delete_item(Item *item) {
|
||||
ent_unregister(&item->ent);
|
||||
objpool_release(stage_object_pools.items, (ObjectInterface*)list_unlink(&global.items, item));
|
||||
objpool_release(stage_object_pools.items, &alist_unlink(&global.items, item)->object_interface);
|
||||
}
|
||||
|
||||
Item* create_bpoint(complex pos) {
|
||||
|
@ -93,7 +93,7 @@ Item* create_bpoint(complex pos) {
|
|||
}
|
||||
|
||||
void delete_items(void) {
|
||||
objpool_release_list(stage_object_pools.items, (List**)&global.items);
|
||||
objpool_release_alist(stage_object_pools.items, &global.items);
|
||||
}
|
||||
|
||||
complex move_item(Item *i) {
|
||||
|
@ -138,7 +138,7 @@ static bool item_out_of_bounds(Item *item) {
|
|||
}
|
||||
|
||||
void process_items(void) {
|
||||
Item *item = global.items, *del = NULL;
|
||||
Item *item = global.items.first, *del = NULL;
|
||||
float r = player_property(&global.plr, PLR_PROP_COLLECT_RADIUS);
|
||||
bool plr_alive = global.plr.deathtime <= global.frames && global.plr.deathtime == -1;
|
||||
bool plr_bombing = global.frames - global.plr.recovery < 0;;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "entity.h"
|
||||
|
||||
typedef struct Item Item;
|
||||
typedef LIST_ANCHOR(Item) ItemList;
|
||||
|
||||
typedef enum {
|
||||
// from least important to most important
|
||||
|
|
16
src/laser.c
16
src/laser.c
|
@ -67,7 +67,7 @@ void lasers_free(void) {
|
|||
static void ent_draw_laser(EntityInterface *ent);
|
||||
|
||||
Laser *create_laser(complex pos, float time, float deathtime, Color color, LaserPosRule prule, LaserLogicRule lrule, complex a0, complex a1, complex a2, complex a3) {
|
||||
Laser *l = (Laser*)list_push(&global.lasers, objpool_acquire(stage_object_pools.lasers));
|
||||
Laser *l = (Laser*)alist_push(&global.lasers, objpool_acquire(stage_object_pools.lasers));
|
||||
|
||||
l->birthtime = global.frames;
|
||||
l->timespan = time;
|
||||
|
@ -216,7 +216,7 @@ static void ent_draw_laser(EntityInterface *ent) {
|
|||
}
|
||||
}
|
||||
|
||||
void* _delete_laser(List **lasers, List *laser, void *arg) {
|
||||
void* _delete_laser(ListAnchor *lasers, List *laser, void *arg) {
|
||||
Laser *l = (Laser*)laser;
|
||||
|
||||
if(l->lrule)
|
||||
|
@ -224,19 +224,19 @@ void* _delete_laser(List **lasers, List *laser, void *arg) {
|
|||
|
||||
del_ref(laser);
|
||||
ent_unregister(&l->ent);
|
||||
objpool_release(stage_object_pools.lasers, (ObjectInterface*)list_unlink(lasers, laser));
|
||||
objpool_release(stage_object_pools.lasers, (ObjectInterface*)alist_unlink(lasers, laser));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void delete_laser(Laser **lasers, Laser *laser) {
|
||||
_delete_laser((List**)lasers, (List*)laser, NULL);
|
||||
void delete_laser(LaserList *lasers, Laser *laser) {
|
||||
_delete_laser((ListAnchor*)lasers, (List*)laser, NULL);
|
||||
}
|
||||
|
||||
void delete_lasers(void) {
|
||||
list_foreach(&global.lasers, _delete_laser, NULL);
|
||||
alist_foreach(&global.lasers, _delete_laser, NULL);
|
||||
}
|
||||
|
||||
bool clear_laser(Laser **laserlist, Laser *l, bool force, bool now) {
|
||||
bool clear_laser(LaserList *laserlist, Laser *l, bool force, bool now) {
|
||||
if(!force && l->unclearable) {
|
||||
return false;
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ bool clear_laser(Laser **laserlist, Laser *l, bool force, bool now) {
|
|||
static bool collision_laser_curve(Laser *l);
|
||||
|
||||
void process_lasers(void) {
|
||||
Laser *laser = global.lasers, *del = NULL;
|
||||
Laser *laser = global.lasers.first, *del = NULL;
|
||||
|
||||
while(laser != NULL) {
|
||||
if(laser->dead) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "entity.h"
|
||||
|
||||
typedef struct Laser Laser;
|
||||
typedef LIST_ANCHOR(Laser) LaserList;
|
||||
|
||||
typedef complex (*LaserPosRule)(Laser* l, float time);
|
||||
typedef void (*LaserLogicRule)(Laser* l, int time);
|
||||
|
@ -64,7 +65,7 @@ Laser *create_laser(complex pos, float time, float deathtime, Color color, Laser
|
|||
void delete_lasers(void);
|
||||
void process_lasers(void);
|
||||
|
||||
bool clear_laser(Laser **laserlist, Laser *l, bool force, bool now);
|
||||
bool clear_laser(LaserList *laserlist, Laser *l, bool force, bool now);
|
||||
|
||||
complex las_linear(Laser *l, float t);
|
||||
complex las_accel(Laser *l, float t);
|
||||
|
|
204
src/list.c
204
src/list.c
|
@ -35,6 +35,35 @@ List* list_insert(List **dest, List *elem) {
|
|||
return elem;
|
||||
}
|
||||
|
||||
List* alist_insert(ListAnchor *list, List *ref, List *elem) {
|
||||
elem->prev = ref;
|
||||
|
||||
if(ref != NULL) {
|
||||
elem->next = ref->next;
|
||||
|
||||
if(elem->next != NULL) {
|
||||
elem->next->prev = elem;
|
||||
}
|
||||
|
||||
if(ref == list->last) {
|
||||
list->last = elem;
|
||||
}
|
||||
|
||||
if(list->first == NULL) {
|
||||
// list->first = elem;
|
||||
}
|
||||
|
||||
ref->next = elem;
|
||||
} else {
|
||||
assert(list->first == NULL);
|
||||
assert(list->last == NULL);
|
||||
elem->next = elem->prev = NULL;
|
||||
list->first = list->last = elem;
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
List* list_push(List **dest, List *elem) {
|
||||
if(*dest) {
|
||||
(*dest)->prev = elem;
|
||||
|
@ -47,6 +76,22 @@ List* list_push(List **dest, List *elem) {
|
|||
return elem;
|
||||
}
|
||||
|
||||
List* alist_push(ListAnchor *list, List *elem) {
|
||||
elem->next = list->first;
|
||||
elem->prev = NULL;
|
||||
|
||||
if(list->last == NULL) {
|
||||
assert(list->first == NULL);
|
||||
list->last = elem;
|
||||
} else {
|
||||
assert(list->first != NULL);
|
||||
list->first->prev = elem;
|
||||
}
|
||||
|
||||
list->first = elem;
|
||||
return elem;
|
||||
}
|
||||
|
||||
List* list_append(List **dest, List *elem) {
|
||||
if(*dest == NULL) {
|
||||
return list_insert(dest, elem);
|
||||
|
@ -60,6 +105,22 @@ List* list_append(List **dest, List *elem) {
|
|||
return list_insert(&end, elem);
|
||||
}
|
||||
|
||||
List* alist_append(ListAnchor *list, List *elem) {
|
||||
elem->next = NULL;
|
||||
elem->prev = list->last;
|
||||
|
||||
if(list->last == NULL) {
|
||||
assert(list->first == NULL);
|
||||
list->first = elem;
|
||||
} else {
|
||||
assert(list->first != NULL);
|
||||
list->last->next = elem;
|
||||
}
|
||||
|
||||
list->last = elem;
|
||||
return elem;
|
||||
}
|
||||
|
||||
attr_hot
|
||||
static List* list_insert_at_priority(List **list_head, List *elem, int prio, ListPriorityFunc prio_func, bool head) {
|
||||
if(!*list_head) {
|
||||
|
@ -112,10 +173,101 @@ List* list_insert_at_priority_head(List **dest, List *elem, int prio, ListPriori
|
|||
return list_insert_at_priority(dest, elem, prio, prio_func, true);
|
||||
}
|
||||
|
||||
List* alist_insert_at_priority_head(ListAnchor *list, List *elem, int prio, ListPriorityFunc prio_func) {
|
||||
if(list->first == NULL) {
|
||||
assert(list->last == NULL);
|
||||
elem->prev = elem->next = NULL;
|
||||
list->first = list->last = elem;
|
||||
return elem;
|
||||
}
|
||||
|
||||
List *dest = list->first;
|
||||
int dest_prio = prio_func(dest);
|
||||
int candidate_prio = dest_prio;
|
||||
|
||||
for(List *e = dest->next; e && (candidate_prio = prio_func(e)) < prio; e = e->next) {
|
||||
dest = e;
|
||||
dest_prio = candidate_prio;
|
||||
}
|
||||
|
||||
if(dest == list->first && dest_prio > prio) {
|
||||
elem->next = dest;
|
||||
elem->prev = dest->prev;
|
||||
|
||||
if(elem->prev) {
|
||||
elem->prev->next = elem;
|
||||
}
|
||||
|
||||
dest->prev = elem;
|
||||
list->first = elem;
|
||||
} else {
|
||||
elem->prev = dest;
|
||||
elem->next = dest->next;
|
||||
|
||||
if(dest->next) {
|
||||
dest->next->prev = elem;
|
||||
} else {
|
||||
assert(dest == list->last);
|
||||
list->last = elem;
|
||||
}
|
||||
|
||||
dest->next = elem;
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
List* list_insert_at_priority_tail(List **dest, List *elem, int prio, ListPriorityFunc prio_func) {
|
||||
return list_insert_at_priority(dest, elem, prio, prio_func, false);
|
||||
}
|
||||
|
||||
List* alist_insert_at_priority_tail(ListAnchor *list, List *elem, int prio, ListPriorityFunc prio_func) {
|
||||
if(list->last == NULL) {
|
||||
assert(list->first == NULL);
|
||||
}
|
||||
|
||||
if(list->first == NULL) {
|
||||
assert(list->last == NULL);
|
||||
elem->prev = elem->next = NULL;
|
||||
list->first = list->last = elem;
|
||||
return elem;
|
||||
}
|
||||
|
||||
List *dest = list->last;
|
||||
int dest_prio = prio_func(dest);
|
||||
|
||||
for(List *e = dest->prev; e && dest_prio > prio; e = e->prev) {
|
||||
dest = e;
|
||||
dest_prio = prio_func(e);
|
||||
}
|
||||
|
||||
if(dest == list->first && dest_prio > prio) {
|
||||
elem->next = dest;
|
||||
elem->prev = dest->prev;
|
||||
|
||||
if(elem->prev) {
|
||||
elem->prev->next = elem;
|
||||
}
|
||||
|
||||
dest->prev = elem;
|
||||
list->first = elem;
|
||||
} else {
|
||||
elem->prev = dest;
|
||||
elem->next = dest->next;
|
||||
|
||||
if(dest->next) {
|
||||
dest->next->prev = elem;
|
||||
} else {
|
||||
assert(dest == list->last);
|
||||
list->last = elem;
|
||||
}
|
||||
|
||||
dest->next = elem;
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
List* list_unlink(List **dest, List *elem) {
|
||||
if(elem->prev != NULL) {
|
||||
elem->prev->next = elem->next;
|
||||
|
@ -132,6 +284,14 @@ List* list_unlink(List **dest, List *elem) {
|
|||
return elem;
|
||||
}
|
||||
|
||||
List* alist_unlink(ListAnchor *list, List *elem) {
|
||||
if(list->last == elem) {
|
||||
list->last = list->last->prev;
|
||||
}
|
||||
|
||||
return list_unlink(&list->first, elem);
|
||||
}
|
||||
|
||||
List* list_pop(List **dest) {
|
||||
if(*dest == NULL) {
|
||||
return NULL;
|
||||
|
@ -140,20 +300,40 @@ List* list_pop(List **dest) {
|
|||
return list_unlink(dest, *dest);
|
||||
}
|
||||
|
||||
List* alist_pop(ListAnchor *list) {
|
||||
if(list->first == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return alist_unlink(list, list->first);
|
||||
}
|
||||
|
||||
void* list_foreach(List **dest, ListForeachCallback callback, void *arg) {
|
||||
List *e = *dest;
|
||||
void *ret = NULL;
|
||||
|
||||
while(e != 0) {
|
||||
void *ret;
|
||||
List *tmp = e;
|
||||
e = e->next;
|
||||
for(List *e = *dest, *next; e; e = next) {
|
||||
next = e->next;
|
||||
|
||||
if((ret = callback(dest, tmp, arg)) != NULL) {
|
||||
if((ret = callback(dest, e, arg)) != NULL) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* alist_foreach(ListAnchor *list, ListAnchorForeachCallback callback, void *arg) {
|
||||
void *ret = NULL;
|
||||
|
||||
for(List *e = list->first, *next; e; e = next) {
|
||||
next = e->next;
|
||||
|
||||
if((ret = callback(list, e, arg)) != NULL) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* list_callback_free_element(List **dest, List *elem, void *arg) {
|
||||
|
@ -162,10 +342,20 @@ void* list_callback_free_element(List **dest, List *elem, void *arg) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void* alist_callback_free_element(ListAnchor *list, List *elem, void *arg) {
|
||||
alist_unlink(list, elem);
|
||||
free(elem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void list_free_all(List **dest) {
|
||||
list_foreach(dest, list_callback_free_element, NULL);
|
||||
}
|
||||
|
||||
void alist_free_all(ListAnchor *list) {
|
||||
alist_foreach(list, alist_callback_free_element, NULL);
|
||||
}
|
||||
|
||||
ListContainer* list_wrap_container(void *data) {
|
||||
ListContainer *c = calloc(1, sizeof(ListContainer));
|
||||
c->data = data;
|
||||
|
|
78
src/list.h
78
src/list.h
|
@ -11,6 +11,8 @@
|
|||
|
||||
typedef struct ListInterface ListInterface;
|
||||
typedef struct List List;
|
||||
typedef struct ListAnchorInterface ListAnchorInterface;
|
||||
typedef struct ListAnchor ListAnchor;
|
||||
typedef struct ListContainer ListContainer;
|
||||
|
||||
#define LIST_INTERFACE_BASE(typename) struct { \
|
||||
|
@ -31,14 +33,38 @@ struct List {
|
|||
LIST_INTERFACE(List);
|
||||
};
|
||||
|
||||
#define LIST_ANCHOR_INTERFACE_BASE(typename) struct { \
|
||||
typename *first; \
|
||||
typename *last; \
|
||||
}
|
||||
|
||||
#define LIST_ANCHOR_INTERFACE(typename) union { \
|
||||
ListAnchorInterface list_anchor_interface; \
|
||||
LIST_ANCHOR_INTERFACE_BASE(typename); \
|
||||
}
|
||||
|
||||
#define LIST_ANCHOR(typename) struct { \
|
||||
LIST_ANCHOR_INTERFACE(typename); \
|
||||
}
|
||||
|
||||
struct ListAnchorInterface {
|
||||
LIST_ANCHOR_INTERFACE_BASE(ListInterface);
|
||||
};
|
||||
|
||||
struct ListAnchor {
|
||||
LIST_ANCHOR_INTERFACE(List);
|
||||
};
|
||||
|
||||
struct ListContainer {
|
||||
LIST_INTERFACE(ListContainer);
|
||||
void *data;
|
||||
};
|
||||
|
||||
typedef void* (*ListForeachCallback)(List **head, List *elem, void *arg);
|
||||
typedef int (*ListPriorityFunc)(List *elem);
|
||||
typedef void* (*ListAnchorForeachCallback)(ListAnchor *list, List *elem, void *arg);
|
||||
typedef List* (*ListInsertionRule)(List **dest, List *elem);
|
||||
typedef List* (*ListAnchorInsertionRule)(ListAnchor *dest, List *elem);
|
||||
typedef int (*ListPriorityFunc)(List *elem);
|
||||
|
||||
List* list_insert(List **dest, List *elem) attr_nonnull(1, 2);
|
||||
List* list_push(List **dest, List *elem) attr_nonnull(1, 2);
|
||||
|
@ -50,6 +76,18 @@ List* list_unlink(List **dest, List *elem) attr_nonnull(1, 2);
|
|||
void* list_foreach(List **dest, ListForeachCallback callback, void *arg) attr_nonnull(1, 2);
|
||||
void* list_callback_free_element(List **dest, List *elem, void *arg);
|
||||
void list_free_all(List **dest) attr_nonnull(1);
|
||||
|
||||
List* alist_insert(ListAnchor *list, List *ref, List *elem) attr_nonnull(1, 3);
|
||||
List* alist_push(ListAnchor *list, List *elem) attr_nonnull(1, 2);
|
||||
List* alist_append(ListAnchor *list, List *elem) attr_nonnull(1, 2);
|
||||
List* alist_insert_at_priority_head(ListAnchor *list, List *elem, int prio, ListPriorityFunc prio_func) attr_hot attr_nonnull(1, 2, 4);
|
||||
List* alist_insert_at_priority_tail(ListAnchor *list, List *elem, int prio, ListPriorityFunc prio_func) attr_hot attr_nonnull(1, 2, 4);
|
||||
List* alist_pop(ListAnchor *list) attr_nonnull(1);
|
||||
List* alist_unlink(ListAnchor *list, List *elem) attr_nonnull(1, 2);
|
||||
void* alist_foreach(ListAnchor *list, ListAnchorForeachCallback callback, void *arg) attr_nonnull(1, 2);
|
||||
void* alist_callback_free_element(ListAnchor *list, List *elem, void *arg);
|
||||
void alist_free_all(ListAnchor *list) attr_nonnull(1);
|
||||
|
||||
ListContainer* list_wrap_container(void *data) attr_nodiscard;
|
||||
|
||||
// type-generic macros
|
||||
|
@ -58,6 +96,7 @@ ListContainer* list_wrap_container(void *data) attr_nodiscard;
|
|||
|
||||
#ifdef USE_GNU_EXTENSIONS
|
||||
// thorough safeguard
|
||||
|
||||
#define LIST_CAST(expr,ptrlevel) (__extension__({ \
|
||||
static_assert(__builtin_types_compatible_p(ListInterface, __typeof__((ptrlevel (expr)).list_interface)), \
|
||||
"struct must implement ListInterface (use the LIST_INTERFACE macro)"); \
|
||||
|
@ -65,10 +104,20 @@ ListContainer* list_wrap_container(void *data) attr_nodiscard;
|
|||
"list_interface must be the first member in struct"); \
|
||||
(List ptrlevel)(expr); \
|
||||
}))
|
||||
|
||||
#define LIST_ANCHOR_CAST(expr,ptrlevel) (__extension__({ \
|
||||
static_assert(__builtin_types_compatible_p(ListAnchorInterface, __typeof__((ptrlevel (expr)).list_anchor_interface)), \
|
||||
"struct must implement ListAnchorInterface (use the LIST_ANCHOR_INTERFACE macro)"); \
|
||||
static_assert(__builtin_offsetof(__typeof__(ptrlevel (expr)), list_anchor_interface) == 0, \
|
||||
"list_anchor_interface must be the first member in struct"); \
|
||||
(ListAnchor ptrlevel)(expr); \
|
||||
}))
|
||||
|
||||
#define LIST_CAST_RETURN(expr) (__typeof__(expr))
|
||||
#else
|
||||
// basic safeguard
|
||||
#define LIST_CAST(expr,ptrlevel) ((void)sizeof((ptrlevel (expr)).list_interface), (List ptrlevel)(expr))
|
||||
#define LIST_ANCHOR_CAST(expr,ptrlevel) ((void)sizeof((ptrlevel (expr)).list_anchor_interface), (ListAnchor ptrlevel)(expr))
|
||||
// don't even think about adding a void* cast here
|
||||
#define LIST_CAST_RETURN(expr)
|
||||
#endif
|
||||
|
@ -76,28 +125,55 @@ ListContainer* list_wrap_container(void *data) attr_nodiscard;
|
|||
#define list_insert(dest,elem) \
|
||||
(LIST_CAST_RETURN(elem) list_insert(LIST_CAST(dest, **), LIST_CAST(elem, *)))
|
||||
|
||||
#define alist_insert(dest,ref,elem) \
|
||||
(LIST_CAST_RETURN(elem) alist_insert(LIST_ANCHOR_CAST(dest, *), LIST_CAST(ref, *), LIST_CAST(elem, *)))
|
||||
|
||||
#define list_push(dest,elem) \
|
||||
(LIST_CAST_RETURN(elem) list_push(LIST_CAST(dest, **), LIST_CAST(elem, *)))
|
||||
|
||||
#define alist_push(dest,elem) \
|
||||
(LIST_CAST_RETURN(elem) alist_push(LIST_ANCHOR_CAST(dest, *), LIST_CAST(elem, *)))
|
||||
|
||||
#define list_append(dest,elem) \
|
||||
(LIST_CAST_RETURN(elem) list_append(LIST_CAST(dest, **), LIST_CAST(elem, *)))
|
||||
|
||||
#define alist_append(dest,elem) \
|
||||
(LIST_CAST_RETURN(elem) alist_append(LIST_ANCHOR_CAST(dest, *), LIST_CAST(elem, *)))
|
||||
|
||||
#define list_insert_at_priority_head(dest,elem,prio,prio_func) \
|
||||
(LIST_CAST_RETURN(elem) list_insert_at_priority_head(LIST_CAST(dest, **), LIST_CAST(elem, *), prio, prio_func))
|
||||
|
||||
#define alist_insert_at_priority_head(dest,elem,prio,prio_func) \
|
||||
(LIST_CAST_RETURN(elem) alist_insert_at_priority_head(LIST_ANCHOR_CAST(dest, *), LIST_CAST(elem, *), prio, prio_func))
|
||||
|
||||
#define list_insert_at_priority_tail(dest,elem,prio,prio_func) \
|
||||
(LIST_CAST_RETURN(elem) list_insert_at_priority_tail(LIST_CAST(dest, **), LIST_CAST(elem, *), prio, prio_func))
|
||||
|
||||
#define alist_insert_at_priority_tail(dest,elem,prio,prio_func) \
|
||||
(LIST_CAST_RETURN(elem) alist_insert_at_priority_tail(LIST_ANCHOR_CAST(dest, *), LIST_CAST(elem, *), prio, prio_func))
|
||||
|
||||
#define list_pop(dest) \
|
||||
(LIST_CAST_RETURN(*(dest)) list_pop(LIST_CAST(dest, **)))
|
||||
|
||||
#define alist_pop(dest) \
|
||||
(LIST_CAST_RETURN((dest)->first) alist_pop(LIST_ANCHOR_CAST(dest, *)))
|
||||
|
||||
#define list_unlink(dest,elem) \
|
||||
(LIST_CAST_RETURN(elem) list_unlink(LIST_CAST(dest, **), LIST_CAST(elem, *)))
|
||||
|
||||
#define alist_unlink(dest,elem) \
|
||||
(LIST_CAST_RETURN(elem) alist_unlink(LIST_ANCHOR_CAST(dest, *), LIST_CAST(elem, *)))
|
||||
|
||||
#define list_foreach(dest,callback,arg) \
|
||||
list_foreach(LIST_CAST(dest, **), callback, arg)
|
||||
|
||||
#define alist_foreach(dest,callback,arg) \
|
||||
alist_foreach(LIST_ANCHOR_CAST(dest, *), callback, arg)
|
||||
|
||||
#define list_free_all(dest) \
|
||||
list_free_all(LIST_CAST(dest, **))
|
||||
|
||||
#define alist_free_all(dest) \
|
||||
alist_free_all(LIST_ANCHOR_CAST(dest, *))
|
||||
|
||||
#endif // LIST_NO_MACROS
|
||||
|
|
|
@ -17,10 +17,22 @@ static void* objpool_release_list_callback(List **dest, List *elem, void *vpool)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void* objpool_release_alist_callback(ListAnchor *list, List *elem, void *vpool) {
|
||||
alist_unlink(list, elem);
|
||||
objpool_release((ObjectPool*)vpool, (ObjectInterface*)elem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#undef objpool_release_list
|
||||
void objpool_release_list(ObjectPool *pool, List **dest) {
|
||||
list_foreach(dest, objpool_release_list_callback, pool);
|
||||
}
|
||||
|
||||
#undef objpool_release_alist
|
||||
void objpool_release_alist(ObjectPool *pool, ListAnchor *list) {
|
||||
alist_foreach(list, objpool_release_alist_callback, pool);
|
||||
}
|
||||
|
||||
bool objpool_is_full(ObjectPool *pool) {
|
||||
ObjectPoolStats stats;
|
||||
objpool_get_stats(pool, &stats);
|
||||
|
|
|
@ -12,6 +12,13 @@
|
|||
#include "objectpool.h"
|
||||
|
||||
void objpool_release_list(ObjectPool *pool, List **dest);
|
||||
void objpool_release_alist(ObjectPool *pool, ListAnchor *list);
|
||||
bool objpool_is_full(ObjectPool *pool);
|
||||
size_t objpool_object_contents_size(ObjectPool *pool);
|
||||
void *objpool_object_contents(ObjectPool *pool, ObjectInterface *obj, size_t *out_size);
|
||||
|
||||
#define objpool_release_list(pool,dest) \
|
||||
objpool_release_list(pool, LIST_CAST(dest, **))
|
||||
|
||||
#define objpool_release_alist(pool,list) \
|
||||
objpool_release_alist(pool, LIST_ANCHOR_CAST(list, *))
|
||||
|
|
18
src/player.c
18
src/player.c
|
@ -41,7 +41,7 @@ double player_property(Player *plr, PlrProperty prop) {
|
|||
}
|
||||
|
||||
static void ent_draw_player(EntityInterface *ent);
|
||||
static Enemy* player_spawn_focus_circle(void);
|
||||
static void player_spawn_focus_circle(Player *plr);
|
||||
|
||||
void player_stage_post_init(Player *plr) {
|
||||
assert(plr->mode != NULL);
|
||||
|
@ -63,7 +63,7 @@ void player_stage_post_init(Player *plr) {
|
|||
plr->ent.draw_func = ent_draw_player;
|
||||
ent_register(&plr->ent, ENT_PLAYER);
|
||||
|
||||
plr->focus_circle = player_spawn_focus_circle();
|
||||
player_spawn_focus_circle(plr);
|
||||
}
|
||||
|
||||
void player_free(Player *plr) {
|
||||
|
@ -73,7 +73,7 @@ void player_free(Player *plr) {
|
|||
|
||||
aniplayer_free(&plr->ani);
|
||||
ent_unregister(&plr->ent);
|
||||
delete_enemy(&plr->focus_circle, plr->focus_circle);
|
||||
delete_enemy(&plr->focus_circle, plr->focus_circle.first);
|
||||
}
|
||||
|
||||
static void player_full_power(Player *plr) {
|
||||
|
@ -193,11 +193,9 @@ static void player_focus_circle_visual(Enemy *e, int t, bool render) {
|
|||
});
|
||||
}
|
||||
|
||||
static Enemy* player_spawn_focus_circle(void) {
|
||||
Enemy *f = NULL;
|
||||
create_enemy_p(&f, 0, ENEMY_IMMUNE, player_focus_circle_visual, player_focus_circle_logic, 0, 0, 0, 0);
|
||||
static void player_spawn_focus_circle(Player *plr) {
|
||||
Enemy *f = create_enemy_p(&plr->focus_circle, 0, ENEMY_IMMUNE, player_focus_circle_visual, player_focus_circle_logic, 0, 0, 0, 0);
|
||||
f->ent.draw_layer = LAYER_PLAYER_FOCUS;
|
||||
return f;
|
||||
}
|
||||
|
||||
static void player_fail_spell(Player *plr) {
|
||||
|
@ -246,7 +244,7 @@ void player_logic(Player* plr) {
|
|||
}
|
||||
|
||||
plr->focus = approach(plr->focus, (plr->inputflags & INFLAG_FOCUS) ? 30 : 0, 1);
|
||||
plr->focus_circle->pos = plr->pos;
|
||||
plr->focus_circle.first->pos = plr->pos;
|
||||
process_enemies(&plr->focus_circle);
|
||||
|
||||
if(plr->mode->procs.think) {
|
||||
|
@ -277,7 +275,7 @@ void player_logic(Player* plr) {
|
|||
|
||||
const int damage = 100;
|
||||
|
||||
for(Enemy *en = global.enemies; en; en = en->next) {
|
||||
for(Enemy *en = global.enemies.first; en; en = en->next) {
|
||||
if(en->hp > ENEMY_IMMUNE) {
|
||||
en->hp -= damage;
|
||||
}
|
||||
|
@ -556,7 +554,7 @@ bool player_updateinputflags(Player *plr, PlrInputFlag flags) {
|
|||
}
|
||||
|
||||
if((flags & INFLAG_FOCUS) && !(plr->inputflags & INFLAG_FOCUS)) {
|
||||
plr->focus_circle->birthtime = global.frames;
|
||||
plr->focus_circle.first->birthtime = global.frames;
|
||||
}
|
||||
|
||||
plr->inputflags = flags;
|
||||
|
|
|
@ -86,8 +86,8 @@ struct Player {
|
|||
|
||||
struct PlayerMode *mode;
|
||||
AniPlayer ani;
|
||||
Enemy *slaves;
|
||||
Enemy *focus_circle;
|
||||
EnemyList slaves;
|
||||
EnemyList focus_circle;
|
||||
|
||||
int inputflags;
|
||||
bool gamepadmove;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
// args are pain
|
||||
static float global_magicstar_alpha;
|
||||
static Enemy *laser_renderer;
|
||||
|
||||
typedef struct MarisaLaserData {
|
||||
struct {
|
||||
|
@ -54,7 +55,7 @@ static void draw_laser_beam(complex src, complex dst, double size, double step,
|
|||
|
||||
static void trace_laser(Enemy *e, complex vel, int damage) {
|
||||
ProjCollisionResult col;
|
||||
Projectile *lproj = NULL;
|
||||
ProjectileList lproj = { .first = NULL };
|
||||
|
||||
MarisaLaserData *ld = REF(e->args[3]);
|
||||
|
||||
|
@ -77,8 +78,8 @@ static void trace_laser(Enemy *e, complex vel, int damage) {
|
|||
int original_hp;
|
||||
} *prev_collisions = NULL;
|
||||
|
||||
while(lproj) {
|
||||
timeofs = trace_projectile(lproj, &col, col_types | PCOL_VOID, timeofs);
|
||||
while(lproj.first) {
|
||||
timeofs = trace_projectile(lproj.first, &col, col_types | PCOL_VOID, timeofs);
|
||||
struct enemy_col *c = NULL;
|
||||
|
||||
if(!first_found) {
|
||||
|
@ -109,7 +110,7 @@ static void trace_laser(Enemy *e, complex vel, int damage) {
|
|||
col.fatal = false;
|
||||
}
|
||||
|
||||
apply_projectile_collision(&lproj, lproj, &col);
|
||||
apply_projectile_collision(&lproj, lproj.first, &col);
|
||||
|
||||
if(col.type == PCOL_BOSS) {
|
||||
assert(!col.fatal);
|
||||
|
@ -181,8 +182,8 @@ static void marisa_laser_slave_visual(Enemy *e, int t, bool render) {
|
|||
return;
|
||||
}
|
||||
|
||||
float laser_alpha = global.plr.slaves->args[0];
|
||||
float star_alpha = global.plr.slaves->args[1] * global_magicstar_alpha;
|
||||
float laser_alpha = laser_renderer->args[0];
|
||||
float star_alpha = laser_renderer->args[1] * global_magicstar_alpha;
|
||||
|
||||
draw_magic_star(e->pos, 0.75 * star_alpha,
|
||||
rgb(1.0, 0.1, 0.1),
|
||||
|
@ -215,7 +216,7 @@ static float get_laser_alpha(Enemy *e, float a) {
|
|||
return min(a, min(1, (global.frames - e->birthtime) * 0.1));
|
||||
}
|
||||
|
||||
#define FOR_EACH_SLAVE(e) for(Enemy *e = global.plr.slaves; e; e = e->next) if(e != renderer)
|
||||
#define FOR_EACH_SLAVE(e) for(Enemy *e = global.plr.slaves.first; e; e = e->next) if(e != renderer)
|
||||
#define FOR_EACH_REAL_SLAVE(e) FOR_EACH_SLAVE(e) if(e->visual_rule == marisa_laser_slave_visual)
|
||||
|
||||
static void marisa_laser_renderer_visual(Enemy *renderer, int t, bool render) {
|
||||
|
@ -343,8 +344,8 @@ static int marisa_laser_slave(Enemy *e, int t) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if(t == EVENT_DEATH && !global.game_over && global.plr.slaves && creal(global.plr.slaves->args[0])) {
|
||||
spawn_laser_fader(e, global.plr.slaves->args[0]);
|
||||
if(t == EVENT_DEATH && !global.game_over && creal(laser_renderer->args[0])) {
|
||||
spawn_laser_fader(e, laser_renderer->args[0]);
|
||||
|
||||
MarisaLaserData *ld = REF(e->args[3]);
|
||||
free(ld);
|
||||
|
@ -488,7 +489,7 @@ static void marisa_laser_bomb(Player *plr) {
|
|||
}
|
||||
|
||||
static void marisa_laser_respawn_slaves(Player *plr, short npow) {
|
||||
Enemy *e = plr->slaves, *tmp;
|
||||
Enemy *e = plr->slaves.first, *tmp;
|
||||
double dmg = 8;
|
||||
|
||||
while(e != 0) {
|
||||
|
@ -517,7 +518,7 @@ static void marisa_laser_respawn_slaves(Player *plr, short npow) {
|
|||
create_enemy_p(&plr->slaves, -17-30.0*I, ENEMY_IMMUNE, marisa_laser_slave_visual, marisa_laser_slave, -4-45.0*I, dmg, -M_PI/60, 0);
|
||||
}
|
||||
|
||||
for(e = plr->slaves; e; e = e->next) {
|
||||
for(e = plr->slaves.first; e; e = e->next) {
|
||||
if(e->logic_rule == marisa_laser_slave) {
|
||||
MarisaLaserData *ld = calloc(1, sizeof(MarisaLaserData));
|
||||
ld->prev_pos = e->pos + plr->pos;
|
||||
|
@ -536,20 +537,19 @@ static void marisa_laser_power(Player *plr, short npow) {
|
|||
}
|
||||
|
||||
static void marisa_laser_init(Player *plr) {
|
||||
create_enemy_p(&plr->slaves, 0, ENEMY_IMMUNE, marisa_laser_renderer_visual, marisa_laser_renderer, 0, 0, 0, 0);
|
||||
plr->slaves->ent.draw_layer = LAYER_PLAYER_SHOT;
|
||||
laser_renderer = create_enemy_p(&plr->slaves, 0, ENEMY_IMMUNE, marisa_laser_renderer_visual, marisa_laser_renderer, 0, 0, 0, 0);
|
||||
laser_renderer->ent.draw_layer = LAYER_PLAYER_SHOT;
|
||||
marisa_laser_respawn_slaves(plr, plr->power);
|
||||
}
|
||||
|
||||
static void marisa_laser_think(Player *plr) {
|
||||
Enemy *laser_renderer = plr->slaves;
|
||||
assert(laser_renderer != NULL);
|
||||
assert(laser_renderer->logic_rule == marisa_laser_renderer);
|
||||
|
||||
if(creal(laser_renderer->args[0]) > 0) {
|
||||
bool found = false;
|
||||
|
||||
for(Projectile *p = global.projs; p && !found; p = p->next) {
|
||||
for(Projectile *p = global.projs.first; p && !found; p = p->next) {
|
||||
if(p->type != EnemyProj) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -252,7 +252,7 @@ static void marisa_star_bombbg(Player *plr) {
|
|||
}
|
||||
|
||||
static void marisa_star_respawn_slaves(Player *plr, short npow) {
|
||||
Enemy *e = plr->slaves, *tmp;
|
||||
Enemy *e = plr->slaves.first, *tmp;
|
||||
double dmg = 56;
|
||||
|
||||
while(e != 0) {
|
||||
|
@ -280,7 +280,7 @@ static void marisa_star_respawn_slaves(Player *plr, short npow) {
|
|||
create_enemy_p(&plr->slaves, -30, ENEMY_IMMUNE, marisa_common_slave_visual, marisa_star_slave, -25+30.0*I, 0.6-2.0*I, -2-0.1*I, dmg);
|
||||
}
|
||||
|
||||
for(Enemy *e = plr->slaves; e; e = e->next) {
|
||||
for(Enemy *e = plr->slaves.first; e; e = e->next) {
|
||||
e->ent.draw_layer = LAYER_PLAYER_SLAVE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include "youmu.h"
|
||||
#include "renderer/api.h"
|
||||
|
||||
#define MYON (global.plr.slaves.first)
|
||||
|
||||
static Color myon_color(float f, float a) {
|
||||
// return rgba(0.8+0.2*f, 0.9-0.4*sqrt(f), 1.0-0.2*f*f, a);
|
||||
// return rgba(0.8+0.2*f, 0.9-0.4*sqrt(f), 1.0-0.4*f*f, a);
|
||||
|
@ -32,7 +34,7 @@ static int myon_particle_rule(Projectile *p, int t) {
|
|||
}
|
||||
|
||||
static complex myon_tail_dir(void) {
|
||||
double angle = carg(global.plr.slaves->args[0]);
|
||||
double angle = carg(MYON->args[0]);
|
||||
complex dir = cexp(I*(0.1 * sin(global.frames * 0.05) + angle));
|
||||
float f = abs(global.plr.focus) / 30.0;
|
||||
return f * f * dir;
|
||||
|
@ -44,7 +46,7 @@ static int myon_flare_particle_rule(Projectile *p, int t) {
|
|||
}
|
||||
|
||||
// wiggle wiggle
|
||||
p->pos += 0.05 * (global.plr.slaves->pos - p->pos) * cexp(I * sin((t - global.frames * 2) * 0.1) * M_PI/8);
|
||||
p->pos += 0.05 * (MYON->pos - p->pos) * cexp(I * sin((t - global.frames * 2) * 0.1) * M_PI/8);
|
||||
p->args[0] = 3 * myon_tail_dir();
|
||||
p->color = derive_color(p->color, CLRMASK_A, rgba(1, 1, 1, pow(1 - min(1, t / (double)p->timeout), 2)));
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ static complex youmu_homing_target(complex org, complex fallback) {
|
|||
mindst = cabs(target - org);
|
||||
}
|
||||
|
||||
for(Enemy *e = global.enemies; e; e = e->next) {
|
||||
for(Enemy *e = global.enemies.first; e; e = e->next) {
|
||||
if(e->hp == ENEMY_IMMUNE){
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -266,7 +266,7 @@ static Projectile* _create_projectile(ProjArgs *args) {
|
|||
// But in that case, code that uses this function's return value must be careful to not dereference a NULL pointer.
|
||||
proj_call_rule(p, EVENT_BIRTH);
|
||||
|
||||
return list_append(args->dest, p);
|
||||
return alist_append(args->dest, p);
|
||||