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.
8 #include "common/llist.h"
11 Caret
*firstcaret
= NULL
;
12 Caret
*lastcaret
= NULL
;
13 static int _effecttype
= EFFECT_NONE
;
16 bool Carets::init(void)
23 void Carets::close(void)
29 void c------------------------------() {}
32 Caret
*CreateCaret(int x
, int y
, int sprite
, void (*ontick
)(Caret
*c
), \
33 int xinertia
, int yinertia
)
36 memset(c
, 0, sizeof(Caret
));
40 c
->xinertia
= xinertia
;
41 c
->yinertia
= yinertia
;
44 c
->effecttype
= _effecttype
;
46 LL_ADD_END(c
, prev
, next
, firstcaret
, lastcaret
);
57 LL_REMOVE(this, prev
, next
, firstcaret
, lastcaret
);
61 void Caret::MoveAtDir(int dir
, int speed
)
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
;
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
);
120 int Carets::CountByEffectType(int type
)
123 Caret
*c
= firstcaret
;
126 if (c
->effecttype
== type
) count
++;
133 int Carets::DeleteByEffectType(int type
)
136 Caret
*c
= firstcaret
;
139 if (c
->effecttype
== type
) c
->Delete();
146 void Carets::DestroyAll(void)
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
)
167 // tell CreateCaret what kind of effect we're spawning
168 _effecttype
= 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
);
190 case EFFECT_GUNFISH_BUBBLE
:
192 c
= CreateCaret(x
-(3<<CSF
), y
-(3<<CSF
), SPR_GUNFISH_BUBBLE
, caret_gunfish_bubble
); break;
196 case EFFECT_LAVA_SPLASH
:
198 c
= CreateCaret(x
-(3<<CSF
), y
-(3<<CSF
), SPR_LAVA_DRIP_SPLASH
, caret_gunfish_bubble
); break;
202 case EFFECT_GHOST_SPARKLE
:
204 c
= CreateCaret(x
, y
, SPR_GHOST_SPARKLE
, caret_ghost_sparkle
);
205 c
->yinertia
= random(-0x600, -0x200);
209 // "blood" spatters from shot hitting enemy
210 case EFFECT_BLOODSPLATTER
:
214 c
= CreateCaret(x
, y
, SPR_BLOODHIT
, caret_animate3
);
215 vector_from_angle(random(0, 255), (2<<CSF
), &c
->xinertia
, &c
->yinertia
);
220 // two little blinky stars when player bonks his head on the ceiling
221 case EFFECT_BONKPLUS
:
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);
238 // only 1 question mark is ever shown at a time
239 DeleteEffectsOfType(EFFECT_QMARK
);
240 c
= CreateCaret(x
, y
, SPR_QMARK
, caret_qmark
);
245 staterr("effect: invalid effect type %d", effectno
);
249 _effecttype
= EFFECT_NONE
;
254 void c------------------------------() {}
257 void caret_animate1(Caret
*c
)
262 void caret_animate2(Caret
*c
)
267 void caret_animate3(Caret
*c
)
272 void Caret::anim(int speed
)
274 Caret
* const &c
= this;
276 if (++c
->animtimer
> speed
)
280 if (++c
->frame
>= sprites
[c
->sprite
].nframes
)
285 void Caret::animdie(int speed
)
287 Caret
* const &c
= this;
289 if (++c
->animtimer
> speed
)
293 if (++c
->frame
>= sprites
[c
->sprite
].nframes
)
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);
316 void caret_fishy(Caret
*c
)
323 void caret_spur_hit(Caret
*c
)
326 c
->frame
= (c
->timer
/ 2) % 3;
333 // "Level Up", "Level Down", and "Empty" texts
334 void caret_playertext(Caret
*c
)
340 // "EMPTY" text goes twice as fast as "Level" text
341 if (c
->sprite
== SPR_EMPTY
)
357 c
->y
-= (spd
<< CSF
);
367 // ? effect when you press down with no object around to activate
368 void caret_qmark(Caret
*c
)
384 void caret_bonusflash(Caret
*c
)
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
)
403 if (c
->yinertia
>= 0x5ff) c
->yinertia
= 0x5ff;
407 void caret_ghost_sparkle(Caret
*c
)
409 c
->invisible
= (++c
->timer
& 2);
416 void caret_zzzz(Caret
*c
)