NXEngine v1.0.0.6
[NXEngine.git] / caret.cpp
blobbe03b1f3415a02b02a941e2b9cd94200ade07114
2 // handle carets; a simplified type of objects used for visual effects.
3 // carets have no interaction with real objects, and are always drawn
4 // on top of all other objects and in front even of map foreground tiles.
6 #include "nx.h"
7 #include <math.h>
8 #include "common/llist.h"
9 #include "caret.fdh"
11 Caret *firstcaret = NULL;
12 Caret *lastcaret = NULL;
13 static int _effecttype = EFFECT_NONE;
16 bool Carets::init(void)
18 firstcaret = NULL;
19 lastcaret = NULL;
20 return 0;
23 void Carets::close(void)
25 Carets::DestroyAll();
29 void c------------------------------() {}
32 Caret *CreateCaret(int x, int y, int sprite, void (*ontick)(Caret *c), \
33 int xinertia, int yinertia)
35 Caret *c = new Caret;
36 memset(c, 0, sizeof(Caret));
38 c->x = x;
39 c->y = y;
40 c->xinertia = xinertia;
41 c->yinertia = yinertia;
42 c->sprite = sprite;
43 c->OnTick = ontick;
44 c->effecttype = _effecttype;
46 LL_ADD_END(c, prev, next, firstcaret, lastcaret);
47 return c;
50 void Caret::Delete()
52 this->deleted = true;
55 void Caret::Destroy()
57 LL_REMOVE(this, prev, next, firstcaret, lastcaret);
58 delete this;
61 void Caret::MoveAtDir(int dir, int speed)
63 this->xinertia = 0;
64 this->yinertia = 0;
66 switch(dir)
68 case LEFT: this->xinertia = -speed; break;
69 case RIGHT: this->xinertia = speed; break;
70 case UP: this->yinertia = -speed; break;
71 case DOWN: this->yinertia = speed; break;
76 void c------------------------------() {}
79 void Carets::DrawAll(void)
81 Caret *c = firstcaret;
82 Caret *next;
83 int scr_x, scr_y;
85 while(c)
87 next = c->next;
89 if (c->deleted)
91 c->Destroy();
93 else
95 // do caret ai
96 (*c->OnTick)(c);
98 // move caret
99 c->x += c->xinertia;
100 c->y += c->yinertia;
102 // get caret's onscreen position
103 // since caret's are all short-lived we just assume it's still onscreen
104 // and let SDL's clipping handle it if not.
105 if (!c->invisible && !c->deleted) // must check deleted again in case handler_function set it
107 scr_x = (c->x >> CSF) - (map.displayed_xscroll >> CSF);
108 scr_y = (c->y >> CSF) - (map.displayed_yscroll >> CSF);
109 scr_x -= sprites[c->sprite].frame[c->frame].dir[0].drawpoint.x;
110 scr_y -= sprites[c->sprite].frame[c->frame].dir[0].drawpoint.y;
112 draw_sprite(scr_x, scr_y, c->sprite, c->frame, RIGHT);
116 c = next;
120 int Carets::CountByEffectType(int type)
122 int count = 0;
123 Caret *c = firstcaret;
124 while(c)
126 if (c->effecttype == type) count++;
127 c = c->next;
130 return count;
133 int Carets::DeleteByEffectType(int type)
135 int count = 0;
136 Caret *c = firstcaret;
137 while(c)
139 if (c->effecttype == type) c->Delete();
140 c = c->next;
143 return count;
146 void Carets::DestroyAll(void)
148 while(firstcaret)
149 firstcaret->Destroy();
153 void c------------------------------() {}
156 // generates a caret-based effect at x, y. Most sprites used for carets have the
157 // drawpoint at their center so the effect is generally centered at that position.
159 // an effect can be just a convenience function for creating a caret
160 // with a particular sprite/ai combo, or it can produce a group of carets
161 // which are always seen together (e.g. bonkplus or bloodspatter).
162 Caret *effect(int x, int y, int effectno)
164 Caret *c;
165 int i;
167 // tell CreateCaret what kind of effect we're spawning
168 _effecttype = effectno;
170 switch(effectno)
172 case EFFECT_STARSOLID: c = CreateCaret(x, y, SPR_STAR_SOLID, caret_animate3); break;
173 case EFFECT_STARPOOF: c = CreateCaret(x, y, SPR_STAR_POOF, caret_animate3); break;
174 case EFFECT_FISHY: c = CreateCaret(x, y, SPR_FISHY, caret_fishy); break;
175 case EFFECT_BOOMFLASH: c = CreateCaret(x, y, SPR_BOOMFLASH, caret_animate3); break;
176 case EFFECT_BUBBLE_BURST: c = CreateCaret(x, y, SPR_BUBBLE_BURST, caret_animate3); break;
177 case EFFECT_SPUR_HIT: c = CreateCaret(x, y, SPR_SPUR_HIT, caret_spur_hit); break;
178 case EFFECT_ZZZZ: c = CreateCaret(x, y, SPR_ZZZZ, caret_zzzz); break;
179 case EFFECT_LEVELUP: c = CreateCaret(x, y, SPR_LEVELUP, caret_playertext); break;
180 case EFFECT_LEVELDOWN: c = CreateCaret(x, y, SPR_LEVELDOWN, caret_playertext); break;
181 case EFFECT_BONUSFLASH: c = CreateCaret(x, y, SPR_SMOKE_CLOUD, caret_bonusflash); break;
182 case EFFECT_HEY: c = CreateCaret(x, y, SPR_HEY, caret_hey); break;
183 case EFFECT_EMPTY: c = CreateCaret(x, y, SPR_EMPTY, caret_playertext); break;
184 case EFFECT_SMOKETRAIL: c = CreateCaret(x, y, SPR_SMOKETRAIL, caret_animate2); break;
186 case EFFECT_SMOKETRAIL_SLOW:
187 c = CreateCaret(x, y, SPR_SMOKETRAIL, caret_animate3);
188 break;
190 case EFFECT_GUNFISH_BUBBLE:
192 c = CreateCaret(x-(3<<CSF), y-(3<<CSF), SPR_GUNFISH_BUBBLE, caret_gunfish_bubble); break;
194 break;
196 case EFFECT_LAVA_SPLASH:
198 c = CreateCaret(x-(3<<CSF), y-(3<<CSF), SPR_LAVA_DRIP_SPLASH, caret_gunfish_bubble); break;
200 break;
202 case EFFECT_GHOST_SPARKLE:
204 c = CreateCaret(x, y, SPR_GHOST_SPARKLE, caret_ghost_sparkle);
205 c->yinertia = random(-0x600, -0x200);
207 break;
209 // "blood" spatters from shot hitting enemy
210 case EFFECT_BLOODSPLATTER:
212 for(i=0;i<3;i++)
214 c = CreateCaret(x, y, SPR_BLOODHIT, caret_animate3);
215 vector_from_angle(random(0, 255), (2<<CSF), &c->xinertia, &c->yinertia);
218 break;
220 // two little blinky stars when player bonks his head on the ceiling
221 case EFFECT_BONKPLUS:
223 for(i=0;i<2;i++)
225 c = CreateCaret(x, y, SPR_BONKHEADPLUS, caret_bonkplus);
227 c->xinertia = random(-0x600, 0x600);
228 c->yinertia = random(-0x200, 0x200);
229 //uint8_t angle = random(-14, 14);
230 //if (random(0, 1)) angle += 128;
231 //vector_from_angle(angle, random(0x200, 0x384), &c->xinertia, &c->yinertia);
234 break;
236 case EFFECT_QMARK:
238 // only 1 question mark is ever shown at a time
239 DeleteEffectsOfType(EFFECT_QMARK);
240 c = CreateCaret(x, y, SPR_QMARK, caret_qmark);
242 break;
244 default:
245 staterr("effect: invalid effect type %d", effectno);
246 return NULL;
249 _effecttype = EFFECT_NONE;
250 return c;
254 void c------------------------------() {}
257 void caret_animate1(Caret *c)
259 c->animdie(0);
262 void caret_animate2(Caret *c)
264 c->animdie(1);
267 void caret_animate3(Caret *c)
269 c->animdie(2);
272 void Caret::anim(int speed)
274 Caret * const &c = this;
276 if (++c->animtimer > speed)
278 c->animtimer = 0;
280 if (++c->frame >= sprites[c->sprite].nframes)
281 c->frame = 0;
285 void Caret::animdie(int speed)
287 Caret * const &c = this;
289 if (++c->animtimer > speed)
291 c->animtimer = 0;
293 if (++c->frame >= sprites[c->sprite].nframes)
294 c->Delete();
299 void c------------------------------() {}
302 // flickers rapidly and decels at exponential speed.
303 // used for the "bonkplus" effect when you bonk your head
304 void caret_bonkplus(Caret *c)
306 c->xinertia *= 4; c->xinertia /= 5;
307 c->yinertia *= 4; c->yinertia /= 5;
309 c->invisible = (++c->timer & 2);
311 if (c->timer > 20)
312 c->Delete();
316 void caret_fishy(Caret *c)
318 c->yinertia -= 16;
319 c->animdie(4);
323 void caret_spur_hit(Caret *c)
325 c->timer++;
326 c->frame = (c->timer / 2) % 3;
328 if (c->timer > 24)
329 c->Delete();
333 // "Level Up", "Level Down", and "Empty" texts
334 void caret_playertext(Caret *c)
336 int spd, stop;
338 c->anim(1);
340 // "EMPTY" text goes twice as fast as "Level" text
341 if (c->sprite == SPR_EMPTY)
343 spd = 2;
344 stop = 18;
346 else
348 spd = 1;
349 stop = 20;
352 c->timer += spd;
353 if (c->timer < 80)
355 if (c->timer < stop)
357 c->y -= (spd << CSF);
360 else
362 c->Delete();
367 // ? effect when you press down with no object around to activate
368 void caret_qmark(Caret *c)
370 if (++c->timer < 40)
372 if (c->timer < 7)
374 c->y -= (3 << CSF);
377 else
379 c->Delete();
384 void caret_bonusflash(Caret *c)
386 if (++c->timer == 4)
387 c->Delete();
391 void caret_hey(Caret *c)
393 if (++c->timer > 30) c->Delete();
394 if (c->timer < 5) c->y -= (1<<CSF);
398 void caret_gunfish_bubble(Caret *c)
400 c->animdie(5);
402 c->yinertia += 0x40;
403 if (c->yinertia >= 0x5ff) c->yinertia = 0x5ff;
407 void caret_ghost_sparkle(Caret *c)
409 c->invisible = (++c->timer & 2);
411 if (c->timer > 20)
412 c->Delete();
416 void caret_zzzz(Caret *c)
418 c->animdie(5);
420 c->x += 0x80;
421 c->y -= 0x80;