1 /*
2  * player.c - player module
3  * Copyright (C) 2008-2010  Alexandre Martins <alemartf(at)gmail(dot)com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include <math.h>
21 #include "actor.h"
22 #include "player.h"
23 #include "brick.h"
24 #include "enemy.h"
25 #include "item.h"
26 #include "items/ring.h"
27 #include "items/falglasses.h"
28 #include "../core/global.h"
29 #include "../core/audio.h"
30 #include "../core/util.h"
31 #include "../core/stringutil.h"
32 #include "../core/timer.h"
33 #include "../core/logfile.h"
34 #include "../core/input.h"
35 #include "../core/sprite.h"
36 #include "../core/soundfactory.h"
37 #include "../scenes/level.h"
38 
39 
40 /* Uncomment to show the collision detectors */
41 /* #define SHOW_COLLISION_DETECTORS */
42 
43 
44 /* private data */
45 #define NATURAL_ANGLE       0
46 #define LOCKACCEL_NONE      0
47 #define LOCKACCEL_LEFT      1
48 #define LOCKACCEL_RIGHT     2
49 static int rings, hundred_rings;
50 static int lives;
51 static int score;
52 static const char *get_sprite_id(int player_type);
53 static void update_shield(player_t *p);
54 static void update_glasses(player_t *p);
55 static void drop_glasses(player_t *p);
56 static int inside_loop(player_t *p);
57 static int got_crushed(player_t *p, brick_t *brick_up, brick_t *brick_right, brick_t *brick_down, brick_t *brick_left);
58 static void stickyphysics_hack(player_t *player, brick_list_t *brick_list, brick_t **brick_downleft, brick_t **brick_down, brick_t **brick_downright);
59 
60 
61 /*
62  * player_create()
63  * Creates a player
64  */
player_create(int type)65 player_t *player_create(int type)
66 {
67     int i;
68     player_t *p = mallocx(sizeof *p);
69 
70     logfile_message("player_create(%d)", type);
71 
72     switch(type) {
73         case PL_SONIC: p->name = str_dup("Surge"); break;
74         case PL_TAILS: p->name = str_dup("Neon"); break;
75         case PL_KNUCKLES: p->name = str_dup("Charge"); break;
76         default: p->name = str_dup("Unknown"); break;
77     }
78 
79     p->type = type;
80     p->actor = actor_create();
81     p->disable_movement = FALSE;
82     p->in_locked_area = FALSE;
83     p->at_some_border = FALSE;
84 
85     p->spin = p->spin_dash = p->braking = p->flying = p->climbing = p->landing = p->spring = FALSE;
86     p->is_fire_jumping = FALSE;
87     p->getting_hit = p->dying = p->dead = p->blinking = FALSE;
88     p->on_moveable_platform = FALSE;
89     p->lock_accel = LOCKACCEL_NONE;
90     p->flight_timer = p->blink_timer = p->death_timer = 0.0;
91     p->disable_jump_for = 0.0;
92 
93     p->glasses = actor_create();
94     p->got_glasses = FALSE;
95 
96     p->shield = actor_create();
97     p->shield_type = SH_NONE;
98 
99     p->invincible = FALSE;
100     p->invtimer = 0;
101     for(i=0; i<PLAYER_MAX_INVSTAR; i++) {
102         p->invstar[i] = actor_create();
103         actor_change_animation(p->invstar[i], sprite_get_animation("SD_INVSTAR", 0));
104     }
105 
106     p->got_speedshoes = FALSE;
107     p->speedshoes_timer = 0;
108 
109     p->disable_wall = PLAYER_WALL_NONE;
110     p->entering_loop = FALSE;
111     p->at_loopfloortop = FALSE;
112     p->bring_to_back = FALSE;
113 
114     switch(p->type) {
115         case PL_SONIC:
116             p->actor->acceleration = 250;
117             p->actor->maxspeed = 700;
118             p->actor->jump_strength = 400;
119             p->actor->input = input_create_user();
120             actor_change_animation( p->actor , sprite_get_animation(get_sprite_id(PL_SONIC), 0) );
121             break;
122 
123         case PL_TAILS:
124             p->actor->acceleration = 200;
125             p->actor->maxspeed = 600;
126             p->actor->jump_strength = 360;
127             p->actor->input = input_create_user();
128             actor_change_animation( p->actor , sprite_get_animation(get_sprite_id(PL_TAILS), 0) );
129             break;
130 
131         case PL_KNUCKLES:
132             p->actor->acceleration = 200;
133             p->actor->maxspeed = 600;
134             p->actor->jump_strength = 360;
135             p->actor->input = input_create_user();
136             actor_change_animation( p->actor , sprite_get_animation(get_sprite_id(PL_KNUCKLES), 0) );
137             break;
138     }
139 
140     hundred_rings = rings = 0;
141     logfile_message("player_create() ok");
142     return p;
143 }
144 
145 
146 /*
147  * player_destroy()
148  * Destroys a player
149  */
player_destroy(player_t * player)150 void player_destroy(player_t *player)
151 {
152     int i;
153 
154     for(i=0; i<PLAYER_MAX_INVSTAR; i++)
155         actor_destroy(player->invstar[i]);
156 
157     actor_destroy(player->glasses);
158     actor_destroy(player->actor);
159     free(player->name);
160     free(player);
161 }
162 
163 
164 
165 /*
166  * player_update()
167  * Updates the player
168  */
player_update(player_t * player,player_t * team[3],brick_list_t * brick_list)169 void player_update(player_t *player, player_t *team[3], brick_list_t *brick_list)
170 {
171     actor_t *act = player->actor;
172 
173     if(player->blinking) {
174         player->blink_timer += timer_get_delta();
175         act->visible = (timer_get_ticks() % 250) < 125;
176         if(player->blink_timer >= PLAYER_MAX_BLINK) {
177             player->getting_hit = player->blinking = FALSE;
178             act->visible = TRUE;
179         }
180     }
181 
182     if(player->disable_movement) {
183         if(player->spin)
184             actor_change_animation(player->actor, sprite_get_animation(get_sprite_id(player->type), 3));
185         else if(player->spring)
186             actor_change_animation(player->actor, sprite_get_animation(get_sprite_id(player->type), 13));
187     }
188     else
189         actor_move(act, player_platform_movement(player, team, brick_list, level_gravity()));
190 }
191 
192 
193 /*
194  * player_render()
195  * Rendering function
196  */
player_render(player_t * player,v2d_t camera_position)197 void player_render(player_t *player, v2d_t camera_position)
198 {
199     actor_t *act = player->actor;
200     v2d_t hot_spot = act->hot_spot;
201     v2d_t position = act->position;
202     v2d_t s_hot_spot = v2d_new(0,0);
203     v2d_t starpos;
204     int i, invangle[PLAYER_MAX_INVSTAR];
205     float x, angoff, ang = act->angle, s_ang = 0;
206 
207 
208 
209     /* invencibility stars */
210     if(player->invincible) {
211         int maxf = sprite_get_animation("SD_INVSTAR", 0)->frame_count;
212         player->invtimer += timer_get_delta();
213 
214         for(i=0; i<PLAYER_MAX_INVSTAR; i++) {
215             invangle[i] = (180*4) * timer_get_ticks()*0.001 + (i+1)*(360/PLAYER_MAX_INVSTAR);
216             starpos.x = 30*cos(invangle[i]*PI/180);
217             starpos.y = ((timer_get_ticks()+i*400)%2000)/40;
218             starpos = v2d_rotate(starpos,ang);
219             player->invstar[i]->position.x = act->position.x + starpos.x;
220             player->invstar[i]->position.y = act->position.y - starpos.y + 5;
221             actor_change_animation_frame(player->invstar[i], random(maxf));
222         }
223 
224         if(player->invtimer >= PLAYER_MAX_INVINCIBILITY)
225             player->invincible = FALSE;
226     }
227 
228 
229     /* shields and glasses */
230     if(player->got_glasses)
231         update_glasses(player);
232 
233     if(player->shield_type != SH_NONE)
234         update_shield(player);
235 
236 
237 
238     /* player's specific routines (before rendering) */
239     switch(player->type) {
240         case PL_SONIC:
241             break;
242 
243         case PL_TAILS:
244             /* tails' jump hack */
245             if(act->is_jumping && act->animation == sprite_get_animation(get_sprite_id(PL_TAILS), 3)) {
246                 int rotate = ((fabs(act->speed.x)>100) || input_button_down(act->input,IB_RIGHT) || input_button_down(act->input,IB_LEFT));
247                 int left = (act->mirror & IF_HFLIP);
248                 act->hot_spot = v2d_new(actor_image(act)->w*0.5, actor_image(act)->h*0.9);
249                 if(act->speed.y > 0 && !rotate) act->hot_spot.x *= 0.9/0.5;
250                 if(act->speed.y < 0) {
251                     angoff = left ? 3*PI/2 : PI/2;
252                     act->angle = ang + angoff;
253                     if(rotate)
254                         act->angle -= (left?-1:1) * (PI/2) * (act->jump_strength+act->speed.y)/act->jump_strength;
255                     else
256                         act->position.x -= actor_image(act)->h*(left?0.5:0.0);
257                 }
258                 else {
259                     angoff = left ? PI/2 : 3*PI/2;
260                     act->angle = ang + angoff;
261                     if(rotate) {
262                         if(act->speed.y < act->jump_strength)
263                             act->angle += (left?-1:1) * (PI/2) * (act->jump_strength-act->speed.y)/act->jump_strength;
264                     }
265                     else
266                         act->position.x += actor_image(act)->h*(left?0.1:-0.2);
267                 }
268 
269                 /* fix shield position */
270                 if(player->shield_type != SH_NONE) {
271                     v2d_t voff;
272                     if(rotate)
273                         voff = v2d_rotate(v2d_new(left?-13:13,-13), -act->angle);
274                     else if(act->mirror & IF_HFLIP)
275                         voff = v2d_new((act->speed.y>0) ? -13 : 13, -15);
276                     else
277                         voff = v2d_new((act->speed.y>0 ? 7 : -7), -15);
278                     s_ang = player->shield->angle;
279                     s_hot_spot = player->shield->hot_spot;
280                     player->shield->position = v2d_add(act->position, voff);
281                 }
282             }
283             break;
284 
285         case PL_KNUCKLES:
286             break;
287     }
288 
289 
290     /* rendering */
291     for(i=0;i<PLAYER_MAX_INVSTAR && player->invincible;i++) {
292         if(invangle[i]%360 >= 180)
293             actor_render(player->invstar[i], camera_position);
294     }
295 
296     x = act->angle;
297     act->angle = (act->is_jumping || player->spin) ? x : old_school_angle(x);
298     actor_render(act, camera_position);
299     act->angle = x;
300 
301     if(player->got_glasses)
302         actor_render(player->glasses, camera_position);
303     if(player->shield_type != SH_NONE)
304         actor_render(player->shield, camera_position);
305     for(i=0;i<PLAYER_MAX_INVSTAR && player->invincible;i++) {
306         if(invangle[i]%360 < 180)
307             actor_render(player->invstar[i], camera_position);
308     }
309 
310 
311     /* player's specific routines (after rendering) */
312     switch(player->type) {
313         case PL_SONIC:
314             break;
315 
316         case PL_TAILS:
317             if(act->is_jumping && act->animation == sprite_get_animation(get_sprite_id(PL_TAILS), 3)) {
318                 act->position = position;
319                 act->angle = ang;
320                 act->hot_spot = hot_spot;
321 
322                 if(player->shield_type != SH_NONE) {
323                     player->shield->angle = s_ang;
324                     player->shield->hot_spot = s_hot_spot;
325                 }
326             }
327             break;
328 
329         case PL_KNUCKLES:
330             break;
331     }
332 
333 
334     /* show collision detectors (debug) */
335 #ifdef SHOW_COLLISION_DETECTORS
336     if(player->type == PL_TAILS) {
337     float diff = -2, sqrsize = 2, top=0, middle=0, lateral=0;
338     int slope = !((fabs(act->angle)<EPSILON)||(fabs(act->angle-PI/2)<EPSILON)||(fabs(act->angle-PI)<EPSILON)||(fabs(act->angle-3*PI/2)<EPSILON));
339     switch(player->type) {
340         case PL_SONIC:
341             if(!slope) { top = 0.7; middle = 0.5; lateral = 0.4; }
342             else       { top = 1.0; middle = 0.8; lateral = 0.5; }
343             break;
344 
345         case PL_TAILS:
346             if(!slope) { top = 0.7; middle = 0.5; lateral = 0.25; }
347             else       { top = 1.0; middle = 0.7; lateral = 0.25; }
348             break;
349 
350         case PL_KNUCKLES:
351             if(!slope) { top = 0.7; middle = 0.5; lateral = 0.25; }
352             else       { top = 1.0; middle = 0.7; lateral = 0.25; }
353             break;
354     }
355     {
356     float frame_width=actor_image(act)->w, frame_height=actor_image(act)->h;
357     float offx=camera_position.x-VIDEO_SCREEN_W/2;
358     float offy=camera_position.y-VIDEO_SCREEN_H/2;
359     v2d_t feet      = act->position;
360     v2d_t up        = v2d_add ( feet , v2d_rotate( v2d_new(0, -frame_height*top+diff), -act->angle) );
361     v2d_t down      = v2d_add ( feet , v2d_rotate( v2d_new(0, -diff), -act->angle) );
362     v2d_t left      = v2d_add ( feet , v2d_rotate( v2d_new(-frame_width*lateral+diff, -frame_height*middle), -act->angle) );
363     v2d_t right     = v2d_add ( feet , v2d_rotate( v2d_new(frame_width*lateral-diff, -frame_height*middle), -act->angle) );
364     v2d_t upleft    = v2d_add ( feet , v2d_rotate( v2d_new(-frame_width*lateral+diff, -frame_height*top+diff), -act->angle) );
365     v2d_t upright   = v2d_add ( feet , v2d_rotate( v2d_new(frame_width*lateral-diff, -frame_height*top+diff), -act->angle) );
366     v2d_t downleft  = v2d_add ( feet , v2d_rotate( v2d_new(-frame_width*lateral+diff, -diff), -act->angle) );
367     v2d_t downright = v2d_add ( feet , v2d_rotate( v2d_new(frame_width*lateral-diff, -diff), -act->angle) );
368     if(player->type == PL_TAILS && act->carrying && fabs(act->angle)<EPSILON) { float h=actor_image(act->carrying)->h, k=act->speed.y>5?h*0.7:0; downleft.y += k; downright.y += k; down.y += k; left.y += h*middle+random(h)-h*0.5; right.y = left.y; }
369     float cd_up[4] = { up.x-sqrsize-offx , up.y-sqrsize-offy , up.x+sqrsize-offx , up.y+sqrsize-offy };
370     float cd_down[4] = { down.x-sqrsize-offx , down.y-sqrsize-offy , down.x+sqrsize-offx , down.y+sqrsize-offy };
371     float cd_left[4] = { left.x-sqrsize-offx , left.y-sqrsize-offy , left.x+sqrsize-offx , left.y+sqrsize-offy };
372     float cd_right[4] = { right.x-sqrsize-offx , right.y-sqrsize-offy , right.x+sqrsize-offx , right.y+sqrsize-offy };
373     float cd_downleft[4] = { downleft.x-sqrsize-offx , downleft.y-sqrsize-offy , downleft.x+sqrsize-offx , downleft.y+sqrsize-offy };
374     float cd_downright[4] = { downright.x-sqrsize-offx , downright.y-sqrsize-offy , downright.x+sqrsize-offx , downright.y+sqrsize-offy };
375     float cd_upright[4] = { upright.x-sqrsize-offx , upright.y-sqrsize-offy , upright.x+sqrsize-offx , upright.y+sqrsize-offy };
376     float cd_upleft[4] = { upleft.x-sqrsize-offx , upleft.y-sqrsize-offy , upleft.x+sqrsize-offx , upleft.y+sqrsize-offy };
377     rectfill(video_get_backbuffer()->data, cd_up[0], cd_up[1], cd_up[2], cd_up[3], 0xFFFFFF);
378     rectfill(video_get_backbuffer()->data, cd_down[0], cd_down[1], cd_down[2], cd_down[3], 0xFFFFFF);
379     rectfill(video_get_backbuffer()->data, cd_left[0], cd_left[1], cd_left[2], cd_left[3], 0xFFFFFF);
380     rectfill(video_get_backbuffer()->data, cd_right[0], cd_right[1], cd_right[2], cd_right[3], 0xFFFFFF);
381     rectfill(video_get_backbuffer()->data, cd_downleft[0], cd_downleft[1], cd_downleft[2], cd_downleft[3], random(0xFFFFFF));
382     rectfill(video_get_backbuffer()->data, cd_downright[0], cd_downright[1], cd_downright[2], cd_downright[3], random(0xFFFFFF));
383     rectfill(video_get_backbuffer()->data, cd_upright[0], cd_upright[1], cd_upright[2], cd_upright[3], random(0xFFFFFF));
384     rectfill(video_get_backbuffer()->data, cd_upleft[0], cd_upleft[1], cd_upleft[2], cd_upleft[3], random(0xFFFFFF));
385     }
386     }
387 #endif
388 }
389 
390 
391 
392 /*
393  * player_platform_movement()
394  * Platform movement. Returns
395  * a delta_space vector.
396  *
397  * Note: the actor's hot spot must
398  * be defined on its feet.
399  */
player_platform_movement(player_t * player,player_t * team[3],brick_list_t * brick_list,float gravity)400 v2d_t player_platform_movement(player_t *player, player_t *team[3], brick_list_t *brick_list, float gravity)
401 {
402     actor_t *act = player->actor;
403     const char *sprite_id = get_sprite_id(player->type);
404     float dt = timer_get_delta();
405     float max_y_speed = 480, friction = 0, gravity_factor = 1.0;
406     float maxspeed = act->maxspeed;
407     v2d_t ds = v2d_new(0,0);
408     int pushing_a_wall;
409     int angle_question;
410     int was_jumping = FALSE;
411     int is_walking = (player->actor->animation == sprite_get_animation(sprite_id, 1));
412     int at_right_border = FALSE, at_left_border = FALSE;
413     int climbing_a_slope = FALSE;
414     int block_tails_flight = FALSE;
415     animation_t *animation = NULL;
416 
417     /* actor's collision detectors */
418     int frame_width = actor_image(act)->w, frame_height = actor_image(act)->h;
419     int slope = !((fabs(act->angle)<EPSILON)||(fabs(act->angle-PI/2)<EPSILON)||(fabs(act->angle-PI)<EPSILON)||(fabs(act->angle-3*PI/2)<EPSILON));
420     float diff = -2, sqrsize = 2, top=0, middle=0, lateral=0;
421     brick_t *brick_up, *brick_down, *brick_right, *brick_left;
422     brick_t *brick_upright, *brick_downright, *brick_downleft, *brick_upleft;
423     brick_t *brick_tmp;
424     v2d_t up, upright, right, downright, down, downleft, left, upleft;
425     v2d_t feet = act->position;
426     switch(player->type) {
427         case PL_SONIC:
428             if(!slope) { top = 0.7; middle = 0.5; lateral = 0.4; }
429             else       { top = 1.0; middle = 0.8; lateral = 0.5; }
430             break;
431 
432         case PL_TAILS:
433             if(!slope) { top = 0.7; middle = 0.5; lateral = 0.25; }
434             else       { top = 1.0; middle = 0.7; lateral = 0.25; }
435             break;
436 
437         case PL_KNUCKLES:
438             if(!slope) { top = 0.7; middle = 0.5; lateral = 0.25; }
439             else       { top = 1.0; middle = 0.7; lateral = 0.25; }
440             break;
441     }
442     up        = v2d_add ( feet , v2d_rotate( v2d_new(0, -frame_height*top+diff), -act->angle) );
443     down      = v2d_add ( feet , v2d_rotate( v2d_new(0, -diff), -act->angle) );
444     left      = v2d_add ( feet , v2d_rotate( v2d_new(-frame_width*lateral+diff, -frame_height*middle), -act->angle) );
445     right     = v2d_add ( feet , v2d_rotate( v2d_new(frame_width*lateral-diff, -frame_height*middle), -act->angle) );
446     upleft    = v2d_add ( feet , v2d_rotate( v2d_new(-frame_width*lateral+diff, -frame_height*top+diff), -act->angle) );
447     upright   = v2d_add ( feet , v2d_rotate( v2d_new(frame_width*lateral-diff, -frame_height*top+diff), -act->angle) );
448     downleft  = v2d_add ( feet , v2d_rotate( v2d_new(-frame_width*lateral+diff, -diff), -act->angle) );
449     downright = v2d_add ( feet , v2d_rotate( v2d_new(frame_width*lateral-diff, -diff), -act->angle) );
450     if(player->type == PL_TAILS && act->carrying && fabs(act->angle)<EPSILON) { float h=actor_image(act->carrying)->h, k=act->speed.y>5?h*0.7:0; downleft.y += k; downright.y += k; down.y += k; left.y += h*middle+random(h)-h*0.5; right.y = left.y; }
451     actor_corners_disable_detection(player->disable_wall & PLAYER_WALL_LEFT, player->disable_wall & PLAYER_WALL_RIGHT, player->disable_wall & PLAYER_WALL_BOTTOM, player->disable_wall & PLAYER_WALL_TOP);
452     actor_corners_set_floor_priority( (player->disable_wall & PLAYER_WALL_BOTTOM) ? FALSE : TRUE );
453     actor_corners_ex(act, sqrsize, up, upright, right, downright, down, downleft, left, upleft, brick_list, &brick_up, &brick_upright, &brick_right, &brick_downright, &brick_down, &brick_downleft, &brick_left, &brick_upleft);
454     actor_corners_restore_floor_priority();
455 
456     /* is the player dying? */
457     if(player->dying) {
458         act->speed.x = 0;
459         act->speed.y = min(max_y_speed, act->speed.y+gravity*dt);
460         act->mirror = IF_NONE;
461         act->angle = 0;
462         act->visible = TRUE;
463         player->blinking = FALSE;
464         player->death_timer += dt;
465         player->dead = (player->death_timer >= 2.5);
466         actor_change_animation(act, sprite_get_animation(sprite_id, 8));
467         return v2d_new(0, act->speed.y*dt + 0.5*gravity*dt*dt);
468     }
469     else if(player->dead)
470         return v2d_new(0,0);
471 
472 
473 
474 
475     /* clouds */
476     actor_handle_clouds(act, diff, &brick_up, &brick_upright, &brick_right, &brick_downright, &brick_down, &brick_downleft, &brick_left, &brick_upleft);
477 
478 
479 
480     /* carry */
481     switch(player->type) {
482         case PL_SONIC: act->carry_offset = v2d_new((act->mirror&IF_HFLIP)?7:-9,-40); break;
483         case PL_TAILS: act->carry_offset = v2d_new((act->mirror&IF_HFLIP)?7:-7,-42); break;
484         case PL_KNUCKLES: act->carry_offset = v2d_new((act->mirror&IF_HFLIP)?7:-7,-42); break;
485     }
486 
487     /* I'm being carried */
488     if(act->carried_by != NULL) {
489         player_t *host = NULL;
490         int i, host_id = 0, my_id = 0;
491         actor_t *car = act->carried_by;
492 
493         /* my id? */
494         for(i=0; i<3; i++) {
495             if(team[i] == player) {
496                 my_id = i;
497                 break;
498             }
499         }
500 
501         /* host = who is carrying me? */
502         for(i=0; i<3; i++) {
503             if(team[i]->actor == car) {
504                 /* I've found the host! */
505                 host = team[i];
506                 host_id = i;
507 
508                 /* setting up some common flags... */
509                 player->disable_wall = host->disable_wall;
510                 player->entering_loop = host->entering_loop;
511                 player->at_loopfloortop = host->at_loopfloortop;
512                 player->bring_to_back = host->bring_to_back;
513 
514                 /* done */
515                 break;
516             }
517         }
518 
519         /* actions */
520         if(host && ((host->type == PL_TAILS && !host->flying) || host->getting_hit || host->dying || host->dead)) { /* what should host do? */
521             /* put me down! */
522             act->position = act->carried_by->position;
523             act->carried_by->carrying = NULL;
524             act->carried_by = NULL;
525         }
526         else if((brick_down && brick_down->brick_ref->angle == 0 && (int)car->speed.y >= 5) || player->getting_hit || player->dying || player->dead) { /* what should I do? */
527             /* put me down! */
528             act->position = act->carried_by->position;
529             act->carried_by->carrying = NULL;
530             act->carried_by = NULL;
531         }
532         else {
533             /* carry me! */
534             v2d_t offset = my_id < host_id ? v2d_multiply(car->speed, dt) : v2d_new(0,0);
535             act->speed = v2d_new(0,0);
536             act->mirror = car->mirror;
537             act->angle = 0;
538             actor_change_animation(act, sprite_get_animation(sprite_id, 25));
539             act->position = v2d_subtract(v2d_add(car->position, offset), act->carry_offset);
540             return v2d_new(0,0);
541         }
542     }
543 
544 
545 
546 
547     /* oh no, I got crushed! */
548     if(got_crushed(player, brick_up, brick_right, brick_down, brick_left)) {
549         player_kill(player);
550         return v2d_new(0,0);
551     }
552 
553 
554     /* speed shoes */
555     if(player->got_speedshoes) {
556         if(player->speedshoes_timer > PLAYER_MAX_SPEEDSHOES)
557             player->got_speedshoes = FALSE;
558         else {
559             maxspeed *= 1.5;
560             player->speedshoes_timer += dt;
561         }
562     }
563 
564     /* if the player jumps inside a loop, enable the floor collision detection */
565     if(inside_loop(player)) {
566         if(act->is_jumping)
567             player->disable_wall &= ~PLAYER_WALL_BOTTOM;
568     }
569 
570 
571     /* disable spring mode */
572     if(player->spring) {
573         if((brick_down && (int)act->speed.y >= 0) || player->flying || player->climbing)
574             player->spring = FALSE;
575     }
576 
577 
578     /* useful flags */
579     pushing_a_wall = ((brick_right && input_button_down(act->input, IB_RIGHT)) || (brick_left && input_button_down(act->input, IB_LEFT))) && brick_down;
580     player->on_moveable_platform = (v2d_magnitude(level_brick_move_actor(brick_down,act)) > EPSILON);
581 
582 
583     /* wall collision */
584     climbing_a_slope = brick_down && ((act->angle > 0 && act->angle < PI/2 && act->speed.x>0) || (act->angle > 3*PI/2 && act->angle < 2*PI && act->speed.x<0));
585     if((climbing_a_slope && (brick_upleft || brick_upright)) || (fabs(act->angle) < EPSILON || fabs(act->angle-PI) < EPSILON)){
586         if(brick_right) {
587             if(brick_right->brick_ref->angle % 90 == 0 && (act->speed.x > EPSILON || right.x > brick_right->x)) {
588                 if(!climbing_a_slope || (climbing_a_slope && brick_right->brick_ref->angle != 90)) {
589                     act->speed.x = 0;
590                     act->position.x = brick_right->x + (feet.x-right.x);
591                     if(!act->is_jumping && !player->flying && !player->climbing && fabs(act->speed.y)<EPSILON)
592                         animation = sprite_get_animation(sprite_id, pushing_a_wall ? 14 : 0);
593                     if(climbing_a_slope) return v2d_new(-5,0);
594                 }
595             }
596         }
597 
598         if(brick_left) {
599             if(brick_left->brick_ref->angle % 90 == 0 && (act->speed.x < -EPSILON || left.x < brick_left->x+brick_left->brick_ref->image->w)) {
600                 if(!climbing_a_slope || (climbing_a_slope && brick_left->brick_ref->angle != 270)) {
601                     act->speed.x = 0;
602                     act->position.x = (brick_left->x+brick_left->brick_ref->image->w) + (feet.x-left.x);
603                     if(!act->is_jumping && !player->flying && !player->climbing && fabs(act->speed.y)<EPSILON)
604                         animation = sprite_get_animation(sprite_id, pushing_a_wall ? 14 : 0);
605                     if(climbing_a_slope) return v2d_new(5,0);
606                 }
607             }
608         }
609 
610         if(act->position.x <= act->hot_spot.x) {
611             player->spin = FALSE;
612             at_left_border = TRUE;
613 
614             if(act->position.x < act->hot_spot.x) {
615                 act->speed.x = 0;
616                 act->position.x = act->hot_spot.x;
617                 if(brick_down) {
618                     pushing_a_wall = TRUE;
619                     animation = sprite_get_animation(sprite_id, 1);
620                 }
621             }
622         }
623 
624         if(act->position.x >= level_size().x - (actor_image(act)->w - act->hot_spot.x)) {
625             player->spin = FALSE;
626             at_right_border = TRUE;
627 
628             if(act->position.x > level_size().x - (actor_image(act)->w - act->hot_spot.x)) {
629                 act->speed.x = 0;
630                 act->position.x = level_size().x - (actor_image(act)->w - act->hot_spot.x);
631                 if(brick_down) {
632                     pushing_a_wall = TRUE;
633                     animation = sprite_get_animation(sprite_id, 1);
634                 }
635             }
636         }
637     }
638 
639 
640     /* y-axis */
641     stickyphysics_hack(player, brick_list, &brick_downleft, &brick_down, &brick_downright);
642     if(!player->climbing) {
643         if(brick_down) {
644             int ang = brick_down->brick_ref->angle;
645             int spin_block;
646             float factor, jump_sensitivity = 1.0;
647             was_jumping = TRUE;
648             act->ignore_horizontal = FALSE;
649             player->is_fire_jumping = FALSE;
650             act->is_jumping = FALSE;
651 
652             /* falling bricks? */
653             if(brick_down->brick_ref && brick_down->brick_ref->behavior == BRB_FALL && brick_down->state == BRS_IDLE)
654                 brick_down->state = BRS_ACTIVE;
655 
656             /* stopped, walking, running, spinning... */
657             if(fabs(act->speed.x) < EPSILON) {
658                 if(ang%180==0) player->spin = FALSE;
659 
660                 /* look down */
661                 if(input_button_down(act->input, IB_DOWN)) {
662                     /* crouch down */
663                     if(!player->spin_dash)
664                         animation = sprite_get_animation(sprite_id, 4);
665 
666                     /* spin dash - start */
667                     if(input_button_pressed(act->input, IB_FIRE1)) {
668                         animation = sprite_get_animation(sprite_id, 6);
669                         player->spin_dash = TRUE;
670                         sound_play( soundfactory_get("charge") );
671                     }
672                 }
673                 else if(!pushing_a_wall) {
674                     if(input_button_down(act->input, IB_UP)) { /* look up */
675                         if(!(is_walking && player->at_some_border))
676                             animation = sprite_get_animation(sprite_id, 5);
677                     }
678                     else if(!inside_loop(player)) {
679                         /* stopped / ledge */
680                         brick_t *minileft, *miniright;
681                         v2d_t vminileft  = v2d_add ( feet , v2d_rotate( v2d_new(-8, 0), -act->angle) );
682                         v2d_t vminiright = v2d_add ( feet , v2d_rotate( v2d_new(5, 0), -act->angle) );
683                         v2d_t v = v2d_new(0,0);
684                         actor_corners_ex(act, sqrsize, v, v, v, vminiright, v, vminileft, v, v, brick_list, NULL, NULL, NULL, &miniright, NULL, &minileft, NULL, NULL);
685                         if(((!miniright && !(act->mirror&IF_HFLIP)) || (!minileft && (act->mirror&IF_HFLIP))) && !player->on_moveable_platform)
686                             animation = sprite_get_animation(sprite_id, 10);
687                         else {
688                             if( !((input_button_down(act->input, IB_LEFT) && (at_left_border || player->at_some_border)) || (input_button_down(act->input, IB_RIGHT) && (at_right_border || player->at_some_border))) )
689                                 animation = sprite_get_animation(sprite_id, 0);
690                             else {
691                                 act->mirror = at_left_border ? IF_HFLIP : IF_NONE;
692                                 animation = sprite_get_animation(sprite_id, 1);
693                             }
694                         }
695                     }
696                     else /* stopped */
697                         animation = sprite_get_animation(sprite_id, 0);
698                 }
699 
700                 /* spin dash */
701                 if(player->spin_dash) {
702 
703                     /* particles */
704                     int a, sd_sig = act->mirror&IF_HFLIP ? 1 : -1, r;
705                     v2d_t sd_relativepos, sd_speed;
706                     image_t *pixel;
707 
708                     for(a=0; a<3; a++) {
709                         r = 128+random(128);
710                         pixel = image_create(1,1);
711                         image_clear(pixel, image_rgb(r,r,r));
712 
713                         sd_relativepos = v2d_new(sd_sig*(7+random(7)), 2);
714                         sd_speed = v2d_new(sd_sig * (50+random(200)), -random(200));
715 
716                         level_create_particle(pixel, v2d_add(act->position,sd_relativepos), sd_speed, TRUE);
717                     }
718 
719                     /* end */
720                     if(input_button_up(act->input, IB_DOWN) || level_editmode()) {
721                         player->spin = TRUE;
722                         player->spin_dash = FALSE;
723                         if( ((act->mirror&IF_HFLIP)&&!brick_left&&!at_left_border) || (!(act->mirror&IF_HFLIP)&&!brick_right&&!at_right_border) )
724                             act->speed.x = ( act->mirror & IF_HFLIP ? -1 : 1 )*maxspeed*1.35;
725                         sound_play( soundfactory_get("release") );
726                         player->disable_jump_for = 0.05; /* disable jumping for how long? */
727                     }
728                 }
729 
730 
731             }
732             else {
733                 if(input_button_down(act->input, IB_DOWN)) {
734                     if(!player->spin)
735                         sound_play( soundfactory_get("roll") );
736                     player->spin = TRUE;
737                 }
738 
739 
740                 if(!player->spin && !player->braking) {
741                     float max_walking_speed = maxspeed * 0.75;
742                     float min_braking_speed = maxspeed * 0.35;
743 
744                     /* animation */
745                     if(fabs(act->speed.x) < max_walking_speed) {
746                         if(!pushing_a_wall && act->speed.y >= 0) {
747                                animation = sprite_get_animation(sprite_id, 1); /* walking animation */
748                                actor_change_animation_speed_factor(act, 0.5 + 1.5*(fabs(act->speed.x) / max_walking_speed)); /* animation speed */
749                         }
750                     }
751                     else
752                         animation = sprite_get_animation(sprite_id, 2); /* running animation */
753 
754                     /* brake */
755                     if(fabs(act->speed.x) >= min_braking_speed) {
756                         if( (input_button_down(act->input, IB_RIGHT)&&(act->speed.x<0)) || (input_button_down(act->input, IB_LEFT)&&(act->speed.x>0)) ) {
757                             sound_play( soundfactory_get("brake") );
758                             player->braking = TRUE;
759                         }
760                     }
761 
762                 }
763                 else if(player->spin)
764                     animation = sprite_get_animation(sprite_id, 3); /* spinning */
765                 else if(player->braking) {
766                     /* particles */
767                     int r, sd_sig = act->mirror&IF_HFLIP ? 1 : -1;
768                     v2d_t sd_relativepos, sd_speed;
769                     image_t *pixel;
770 
771                     r = 128+random(128);
772                     pixel = image_create(1,1);
773                     image_clear(pixel, image_rgb(r,r,r));
774                     sd_relativepos = v2d_new(sd_sig*(10-random(21)), 0);
775                     sd_speed = v2d_new(sd_sig * (50+random(200)), -random(200));
776                     level_create_particle(pixel, v2d_add(act->position,sd_relativepos), sd_speed, TRUE);
777 
778                     /* braking */
779                     animation = sprite_get_animation(sprite_id, 7);
780                     if(fabs(act->speed.x)<10) player->braking = FALSE;
781                 }
782             }
783 
784             /* disable jump? */
785             player->disable_jump_for = max(player->disable_jump_for - dt, 0.0);
786             if(fabs(act->speed.x) < EPSILON)
787                 player->disable_jump_for = 0.0;
788 
789             /* jump */
790             spin_block = !player->spin_dash;
791             if(input_button_down(act->input, IB_FIRE1) && (player->disable_jump_for <= 0.0) && !input_button_down(act->input, IB_DOWN) && !brick_up && !player->landing && spin_block && !act->is_jumping) {
792                 if(act->speed.y >= 0 && (player->type != PL_KNUCKLES || (player->type == PL_KNUCKLES && !player->flying)))
793                     sound_play( soundfactory_get("jump") );
794                 act->angle = NATURAL_ANGLE;
795                 act->is_jumping = TRUE;
796                 player->is_fire_jumping = TRUE;
797                 block_tails_flight = TRUE;
798                 player->spin = FALSE;
799                 animation = sprite_get_animation(sprite_id, 3);
800                 if(ang == 0) {
801                     act->speed.y = (-act->jump_strength) * jump_sensitivity;
802                 }
803                 else if(ang > 0 && ang < 90) {
804                     if(ang > 45) {
805                         act->speed.x = min(act->speed.x, (-0.7*act->jump_strength) * jump_sensitivity);
806                         act->speed.y = (-0.7*act->jump_strength) * jump_sensitivity;
807                     }
808                     else {
809                         act->speed.x *= act->speed.x > 0 ? 0.5 : 1.0;
810                         act->speed.y = (-act->jump_strength) * jump_sensitivity;
811                     }
812                 }
813                 else if(ang == 90) {
814                     actor_move(act, v2d_new(20*diff, 0));
815                     act->speed.x = min(act->speed.x, (-act->jump_strength) * jump_sensitivity);
816                     act->speed.y = (-act->jump_strength/2) * jump_sensitivity;
817                 }
818                 else if(ang > 90 && ang < 180) {
819                     actor_move(act, v2d_new(0, -20*diff));
820                     act->speed.x = min(act->speed.x, (-0.7*act->jump_strength) * jump_sensitivity);
821                     act->speed.y = (act->jump_strength) * jump_sensitivity;
822                 }
823                 else if(ang == 180) {
824                     actor_move(act, v2d_new(0, -20*diff));
825                     act->speed.x *= -1;
826                     act->speed.y = (act->jump_strength) * jump_sensitivity;
827                 }
828                 else if(ang > 180 && ang < 270) {
829                     actor_move(act, v2d_new(0, -20*diff));
830                     act->speed.x = max(act->speed.x, (0.7*act->jump_strength) * jump_sensitivity);
831                     act->speed.y = (act->jump_strength) * jump_sensitivity;
832                 }
833                 else if(ang == 270) {
834                     actor_move(act, v2d_new(-20*diff, 0));
835                     act->speed.x = max(act->speed.x, (act->jump_strength) * jump_sensitivity);
836                     act->speed.y = (-act->jump_strength/2) * jump_sensitivity;
837                 }
838                 else if(ang > 270 && ang < 360) {
839                     if(ang < 315) {
840                         act->speed.x = max(act->speed.x, (0.7*act->jump_strength) * jump_sensitivity);
841                         act->speed.y = (-0.7*act->jump_strength) * jump_sensitivity;
842                     }
843                     else {
844                         act->speed.x *= act->speed.x < 0 ? 0.5 : 1.0;
845                         act->speed.y = (-act->jump_strength) * jump_sensitivity;
846                     }
847                 }
848             }
849 
850 
851             /* slopes / speed issues */
852             if(!act->is_jumping) {
853                 float mytan, super = 1.2, push = 25.0;
854                 if(ang > 0 && ang < 90) {
855                     mytan = min(1, tan( ang*PI/180.0 ))*0.8;
856                     if(fabs(act->speed.y) > EPSILON)
857                         act->speed.x = (was_jumping && ang<=45) ? act->speed.x : max(-super*maxspeed, -1*mytan*act->speed.y);
858                     else {
859                         factor = (!(act->mirror & IF_HFLIP) ? 1.0 : 2.0) * mytan;
860                         if(player->braking && ang<45)
861                             factor *= 8.0 * (act->speed.x<0 ? -1.0/2.0 : 1.0/1.0);
862                         else if(fabs(act->speed.x)<5) {
863                             factor *= sin(ang*PI/180.0)*push;
864                             player->lock_accel = LOCKACCEL_RIGHT;
865                         }
866                         act->speed.x = max(act->speed.x - factor*700*dt, -super*maxspeed);
867                     }
868                 }
869                 else if(ang > 270 && ang < 360) {
870                     mytan = min(1, -tan( ang*PI/180.0 ))*0.8;
871                     if(fabs(act->speed.y) > EPSILON)
872                         act->speed.x = (was_jumping && ang>=315) ? act->speed.x : min(super*maxspeed, 1*mytan*act->speed.y);
873                     else {
874                         factor = ((act->mirror & IF_HFLIP) ? 1.0 : 2.0) * mytan;
875                         if(player->braking && ang>315)
876                             factor *= 8.0 * (act->speed.x>0 ? -1.0/2.0 : 1.0/1.0);
877                         else if(fabs(act->speed.x)<5) {
878                             factor *= -sin(ang*PI/180.0)*push;
879                             player->lock_accel = LOCKACCEL_LEFT;
880                         }
881                         act->speed.x = min(act->speed.x + factor*700*dt, super*maxspeed);
882                     }
883                 }
884             }
885 
886             if(ang%90 == 0)
887                 player->lock_accel = LOCKACCEL_NONE;
888 
889             if(brick_downleft && brick_downright && fabs(act->speed.x) < 40) {
890                 if(brick_downleft->brick_ref->angle > 270 && brick_downleft->brick_ref->angle < 360 && brick_downright->brick_ref->angle > 0 && brick_downright->brick_ref->angle < 90) {
891                     if(!input_button_down(act->input, IB_LEFT) && !input_button_down(act->input, IB_RIGHT))
892                         act->speed.x = 0;
893                 }
894             }
895         }
896         else { /* not brick_down */
897             player->braking = FALSE;
898             player->lock_accel = LOCKACCEL_NONE;
899 
900             if(player->spin_dash) {
901                 player->spin_dash = FALSE;
902                 animation = sprite_get_animation(sprite_id, 1);
903             }
904 
905             if(act->animation == sprite_get_animation(sprite_id, 0) || act->animation == sprite_get_animation(sprite_id, 10) || act->animation == sprite_get_animation(sprite_id, 5))
906                 animation = sprite_get_animation(sprite_id, 1);
907 
908             if(player->spring || is_walking || act->speed.y < 0)
909                 player->spin = FALSE;
910 
911             if(!inside_loop(player))
912                 act->angle = NATURAL_ANGLE;
913         }
914 
915 
916         /* jump sensitivity */
917         if(!brick_down) {
918             if(player->is_fire_jumping && act->speed.y < -act->jump_strength*PLAYER_JUMP_SENSITIVITY) {
919                 if(input_button_up(act->input, IB_FIRE1))
920                     act->speed.y *= 0.7;
921             }
922         }
923 
924         /* who can fly? */
925         if(player->type == PL_TAILS && player->flying) {
926             gravity_factor = (player->flight_timer < TAILS_MAX_FLIGHT) ? 0.15 : 0.8;
927             max_y_speed *= 0.3;
928         }
929         else
930             gravity_factor = 1.0;
931 
932         /* y-axis movement */
933         ds.y = (fabs(act->speed.y) > EPSILON) ? act->speed.y*dt + 0.5*(gravity*gravity_factor)*(dt*dt) : 0;
934         if(!(player->type == PL_KNUCKLES && player->flying))
935             act->speed.y = min(act->speed.y + (gravity*gravity_factor)*dt, max_y_speed);
936 
937 
938 
939 
940         /* ceiling collision */
941         angle_question = (brick_up && brick_up->brick_ref->angle%90!=0) && fabs(act->angle)<EPSILON;
942         if(brick_up && (brick_up->brick_ref->angle % 90 == 0 || angle_question) && act->speed.y < -EPSILON) {
943             act->position.y = (brick_up->y+brick_up->brick_ref->image->h) + (feet.y-up.y);
944             act->speed.y = 10;
945 
946             /* this is a moving brick... and it's moving down */
947             if(brick_up->brick_ref->behavior == BRB_CIRCULAR) {
948                 if(sin(brick_up->brick_ref->behavior_arg[3] * brick_up->value[0]) > 0) {
949                     act->speed.y = 100;
950                     ds = v2d_add(ds, v2d_multiply(level_brick_move_actor(brick_up, act), dt));
951                     return ds;
952                 }
953             }
954         }
955 
956 
957 
958         /* floor collision */
959         brick_tmp = brick_down;
960         if(brick_tmp && !act->is_jumping) {
961             int ang = brick_tmp->brick_ref->angle;
962             act->speed.y = ds.y = 0;
963             act->angle = ang * PI / 180.0;
964 
965             /* 0 floor */
966             if(ang == 0) {
967                 v2d_t mov = level_brick_move_actor(brick_down, act); /* moveable platforms I */
968                 feet.y = brick_tmp->y;
969                 friction = 0;
970                 if(mov.y > EPSILON) /* if the moveable brick is going down... */
971                     ds.y += mov.y*dt;
972                 else
973                     act->position.y = feet.y+diff+1;
974             }
975 
976             /* (0-90) slope */
977             else if(ang > 0 && ang < 90) {
978                 feet.y = brick_tmp->y + brick_tmp->brick_ref->image->h - (act->position.x-brick_tmp->x)*tan(act->angle);
979                 if(act->speed.x<0) feet.y += 2.0;
980                 act->position.y = feet.y+diff;
981                 if(!(act->mirror & IF_HFLIP)) friction = 0.2;
982             }
983 
984             /* 90 wall */
985             else if(ang == 90) {
986                 if(fabs(act->speed.x) > 5) {
987                     int myang = brick_downright ? brick_downright->brick_ref->angle : -1;
988                     if(brick_downright && (myang >= ang && myang < ang+90)) {
989                         feet.y = brick_tmp->x;
990                         if(!player->flying) act->position.x = feet.y+diff;
991                     }
992                     else {
993                         act->angle = NATURAL_ANGLE;
994                         act->is_jumping = TRUE;
995                         if(!player->spin && !player->flying) animation = sprite_get_animation(sprite_id, 1);
996                         if(!inside_loop(player)) {
997                             if(!player->flying) actor_move(act, v2d_new(6.5*diff, 0));
998                             act->speed = v2d_new(0, -0.9*fabs(act->speed.x));
999                         }
1000                     }
1001                 }
1002                 else {
1003                     act->angle = NATURAL_ANGLE;
1004                     if(!player->flying) actor_move(act, v2d_new(5*diff, 0));
1005                     act->is_jumping = TRUE;
1006                     act->ignore_horizontal = FALSE;
1007                 }
1008                 if(!(act->mirror & IF_HFLIP)) friction = 1.5;
1009             }
1010 
1011             /* (90-180) slope */
1012             else if(ang > 90 && ang < 180) {
1013                 if(fabs(act->speed.x) > 5) {
1014                     feet.y = brick_tmp->y - (act->position.x-brick_tmp->x)*tan(act->angle);
1015                     act->position.y = feet.y-diff;
1016                 }
1017                 else {
1018                     act->angle = NATURAL_ANGLE;
1019                     actor_move(act, v2d_new(0, -15*diff));
1020                     act->is_jumping = TRUE;
1021                 }
1022                 friction = 1.5;
1023             }
1024 
1025             /* 180 ceiling */
1026             else if(ang == 180) {
1027                 if(fabs(act->speed.x) > 5) {
1028                     feet.y = brick_tmp->y + brick_tmp->brick_ref->image->h;
1029                     act->position.y = feet.y-diff;
1030 
1031                     /* end of ceil */
1032                     if( (act->speed.x > 0 && !brick_downright) || (act->speed.x < 0 && !brick_downleft) ) {
1033                         actor_move(act, v2d_new(0, 15*diff));
1034                         act->is_jumping = TRUE;
1035                         act->speed.x *= -1;
1036                         act->mirror = act->speed.x<0 ? IF_HFLIP : IF_NONE;
1037                         act->angle = NATURAL_ANGLE;
1038                     }
1039                 }
1040                 else {
1041                     act->angle = NATURAL_ANGLE;
1042                     actor_move(act, v2d_new(0, -20*diff));
1043                     act->is_jumping = TRUE;
1044                     act->speed.x = 0;
1045                 }
1046                 friction = 1.2;
1047             }
1048 
1049             /* (180-270) slope */
1050             else if(ang > 180 && ang < 270) {
1051                 if(fabs(act->speed.x) > 5) {
1052                     feet.y = brick_tmp->y + brick_tmp->brick_ref->image->h - (act->position.x-brick_tmp->x)*tan(act->angle);
1053                     act->position.y = feet.y-diff;
1054                 }
1055                 else {
1056                     act->angle = NATURAL_ANGLE;
1057                     actor_move(act, v2d_new(0, -15*diff));
1058                     act->is_jumping = TRUE;
1059                 }
1060                 friction = 1.5;
1061             }
1062 
1063             /* 270 wall */
1064             else if(ang == 270) {
1065                 if(fabs(act->speed.x) > 5) {
1066                     int myang = brick_downleft ? brick_downleft->brick_ref->angle : -1;
1067                     if(brick_downleft && (myang > ang-90 && myang <= ang)) {
1068                         feet.y = brick_tmp->x + brick_tmp->brick_ref->image->w;
1069                         if(!player->flying) act->position.x = feet.y-diff;
1070                     }
1071                     else {
1072                         act->angle = NATURAL_ANGLE;
1073                         act->is_jumping = TRUE;
1074                         if(!player->spin && !player->flying) animation = sprite_get_animation(sprite_id, 1);
1075                         if(!inside_loop(player)) {
1076                             if(!player->flying) actor_move(act, v2d_new(-6.5*diff, 0));
1077                             act->speed = v2d_new(0, -0.9*fabs(act->speed.x));
1078                         }
1079                     }
1080 
1081                 }
1082                 else {
1083                     act->angle = NATURAL_ANGLE;
1084                     if(!player->flying) actor_move(act, v2d_new(-5*diff, 0));
1085                     act->is_jumping = TRUE;
1086                     act->ignore_horizontal = FALSE;
1087                 }
1088                 if(act->mirror & IF_HFLIP) friction = 1.5;
1089             }
1090 
1091             /* (270-360) slope */
1092             else if(ang > 270 && ang < 360) {
1093                 feet.y = brick_tmp->y - (act->position.x-brick_tmp->x)*tan(act->angle);
1094                 if(act->speed.x>0) feet.y += 2.0;
1095                 act->position.y = feet.y+diff;
1096                 if(act->mirror & IF_HFLIP) friction = 0.2;
1097             }
1098         }
1099 
1100 
1101         /* x-axis */
1102         ds.x = (fabs(act->speed.x) > EPSILON) ? act->speed.x*dt + 0.5*((1.0-friction)*act->acceleration)*(dt*dt) : 0;
1103         if(input_button_down(act->input, IB_LEFT) && !input_button_down(act->input, IB_RIGHT) && !player->spin && !player->braking && !player->landing && !player->getting_hit && player->lock_accel != LOCKACCEL_LEFT && !at_left_border) {
1104             if(!act->ignore_horizontal && (act->is_jumping || player->spring || is_walking || !input_button_down(act->input, IB_DOWN))) {
1105                 act->mirror = IF_HFLIP;
1106                 friction = (act->speed.x > 0) ? -1.0 : friction;
1107                 if(act->speed.x >= -maxspeed*1.1)
1108                     act->speed.x = max(act->speed.x - (1.0-friction)*act->acceleration*dt, -maxspeed);
1109             }
1110         }
1111         else if(input_button_down(act->input, IB_RIGHT) && !input_button_down(act->input, IB_LEFT) && !player->spin && !player->braking && !player->landing && !player->getting_hit && player->lock_accel != LOCKACCEL_RIGHT && !at_right_border) {
1112             if(!act->ignore_horizontal && (act->is_jumping || player->spring || is_walking || !input_button_down(act->input, IB_DOWN))) {
1113                 act->mirror = IF_NONE;
1114                 friction = (act->speed.x < 0) ? -1.0 : friction;
1115                 if(act->speed.x <= maxspeed*1.1)
1116                     act->speed.x = min(act->speed.x + (1.0-friction)*act->acceleration*dt, maxspeed);
1117             }
1118         }
1119         else if(brick_down) {
1120             int signal = 0;
1121             int ang = brick_down->brick_ref->angle;
1122             float factor;
1123 
1124             /* deceleration factor */
1125             if(player->spin)
1126                 factor = 0.65;
1127             else if(player->braking)
1128                 factor = 4.5;
1129             else if(player->landing)
1130                 factor = 0.6;
1131             else
1132                 factor = 1.0;
1133 
1134             /* deceleration */
1135             if(ang % 90 == 0) {
1136                 if(ang == 90)
1137                     signal = -1;
1138                 else if(ang == 270)
1139                     signal = 1;
1140                 else {
1141                     if(act->speed.x > EPSILON) signal = -1;
1142                     else if(-act->speed.x > EPSILON) signal = 1;
1143                     else signal = 0;
1144                 }
1145             }
1146             else if((ang > 90 && ang < 180) || (ang > 180 && ang < 270)){
1147                 if(act->speed.x > EPSILON) signal = -1;
1148                 else if(-act->speed.x > EPSILON) signal = 1;
1149                 else signal = 0;
1150             }
1151 
1152             act->speed.x += signal*factor*act->acceleration*dt;
1153         }
1154     }
1155 
1156 
1157     /* spring mode */
1158     if(player->spring) {
1159         animation = sprite_get_animation(sprite_id, act->speed.y <= 0 ? 13 : 1);
1160         if(act->speed.y > 0) {
1161             player->spring = FALSE;
1162             act->is_jumping = FALSE;
1163         }
1164     }
1165 
1166 
1167     /* got hurt? */
1168     if(player->getting_hit) {
1169         if(!brick_down)
1170             animation = sprite_get_animation(sprite_id, 11);
1171         else
1172             player->getting_hit = FALSE;
1173     }
1174 
1175 
1176 
1177     /* character's specific routines */
1178     switch(player->type) {
1179         case PL_SONIC:
1180             break;
1181 
1182         case PL_TAILS:
1183             /* tails can fly */
1184             player->flight_timer += dt;
1185             if(brick_down && brick_down->brick_ref->angle != 90 && brick_down->brick_ref->angle != 270) { player->flying = FALSE; player->flight_timer = 0; }
1186             if(((act->is_jumping && act->speed.y>-act->jump_strength/3 && !block_tails_flight && !player->getting_hit) || player->flying) && input_button_pressed(act->input, IB_FIRE1) && !player->getting_hit) {
1187                 if(player->flight_timer < TAILS_MAX_FLIGHT) {
1188                     if(!player->flying) player->flight_timer = 0;
1189                     act->speed.y = -level_gravity()*0.1;
1190                     player->flying = TRUE;
1191                     act->is_jumping = FALSE;
1192                     player->is_fire_jumping = FALSE;
1193                 }
1194             }
1195             if(player->flying) {
1196                 animation = sprite_get_animation(sprite_id, act->carrying ? 16 : 20);
1197                 act->speed.x = clip(act->speed.x, -act->maxspeed/2, act->maxspeed/2);
1198                 if(player->flight_timer >= TAILS_MAX_FLIGHT) {
1199                     /* i'm tired of flying... */
1200                     sound_t *smp = soundfactory_get("tired of flying");
1201                     if(!sound_is_playing(smp)) sound_play(smp);
1202                     animation = sprite_get_animation(sprite_id, 19);
1203                 }
1204                 else {
1205                     sound_t *smp;
1206                     int i;
1207 
1208                     /* i'm flying! :) */
1209                     if(inside_loop(player)) act->angle = NATURAL_ANGLE;
1210                     smp = soundfactory_get("flying");
1211                     if(!sound_is_playing(smp)) sound_play(smp);
1212 
1213                     /* pick up: let's carry someone... */
1214                     for(i=0; i<3 && act->carrying == NULL; i++) {
1215                         if(team[i] != player && (int)act->speed.y <= 0) {
1216                             float ra[4] = { team[i]->actor->position.x+actor_image(team[i]->actor)->w*0.3, team[i]->actor->position.y, team[i]->actor->position.x+actor_image(team[i]->actor)->w*0.7, team[i]->actor->position.y+actor_image(team[i]->actor)->h*0.2 };
1217                             float rb[4] = { act->position.x+actor_image(act)->w*0.3, act->position.y+actor_image(act)->h*0.7, act->position.x+actor_image(act)->w*0.7, act->position.y+actor_image(act)->h };
1218                             int collision = bounding_box(ra, rb);
1219                             int can_be_carried = (team[i]->actor->carried_by == NULL && !team[i]->dying && !team[i]->dead && !team[i]->climbing && !team[i]->landing && !team[i]->getting_hit);
1220                             if(collision && can_be_carried && !brick_down) {
1221                                 act->carrying = team[i]->actor;
1222                                 team[i]->actor->carried_by = act;
1223                                 team[i]->spin = team[i]->spin_dash = team[i]->braking = team[i]->flying = team[i]->spring = team[i]->on_moveable_platform = FALSE;
1224                                 sound_play( soundfactory_get("touch the wall") );
1225                             }
1226                         }
1227                     }
1228                 }
1229             }
1230             else if(act->animation == sprite_get_animation(sprite_id, act->carrying ? 16 : 20))
1231                 animation = sprite_get_animation(sprite_id, 1); /* if you're not flying, don't play the flying animation */
1232 
1233             break;
1234 
1235         case PL_KNUCKLES:
1236             /* knuckles can fly too! */
1237             if(((act->is_jumping && act->speed.y>-0.7*act->jump_strength) || player->flying) && input_button_pressed(act->input, IB_FIRE1) && !brick_down && !player->getting_hit) {
1238                 act->speed.y = 50;
1239                 player->flying = TRUE;
1240                 act->is_jumping = FALSE;
1241                 player->is_fire_jumping = FALSE;
1242                 act->speed.x = (act->mirror & IF_HFLIP) ? min(-100, act->speed.x) : max(100, act->speed.x);
1243             }
1244 
1245 
1246             /* fly? */
1247             if(player->flying) {
1248                 int turning = (input_button_down(act->input, IB_LEFT) && act->speed.x > 0) || (input_button_down(act->input, IB_RIGHT) && act->speed.x < 0);
1249                 int floor = (brick_down && fabs(brick_down->brick_ref->angle*PI/180.0 - NATURAL_ANGLE) < EPSILON);
1250                 turning += (act->animation == sprite_get_animation(sprite_id, 21)) && !actor_animation_finished(act);
1251 
1252                 /* i'm flying... */
1253                 if(!floor && act->animation != sprite_get_animation(sprite_id, 19) && !player->landing) {
1254                     if(!(act->mirror & IF_HFLIP)) {
1255                         animation = sprite_get_animation(sprite_id, turning ? 21 : 20);
1256                         act->speed.x = min(act->speed.x + (0.5*act->acceleration)*dt, maxspeed/2);
1257                     }
1258                     else {
1259                         animation = sprite_get_animation(sprite_id, turning ? 21 : 20);
1260                         act->speed.x = max(act->speed.x - (0.5*act->acceleration)*dt, -maxspeed/2);
1261                     }
1262                 }
1263 
1264                 /* end of flight */
1265                 if(floor) {
1266                     /* collided with the floor */
1267                     player->landing = TRUE;
1268                     act->is_jumping = FALSE;
1269                     animation = sprite_get_animation(sprite_id, 19);
1270                     act->speed.y = 0; ds.y = 0;
1271                     player->climbing = FALSE;
1272                 }
1273                 else if(input_button_up(act->input, IB_FIRE1)) {
1274                     /* knuckles doesn't want to fly anymore */
1275                     player->flying = FALSE;
1276                     animation = sprite_get_animation(sprite_id, 18);
1277                 }
1278                 else {
1279                     int t;
1280                     brick_t *try_me[5] = { brick_left , brick_downleft , brick_right , brick_downright , brick_down };
1281                     for(t=0; t<5; t++) {
1282                         brick_tmp = try_me[t];
1283                         if(brick_tmp && brick_tmp->brick_ref->angle%90!=0) {
1284                             /* collided with a slope while flying? */
1285                             player->flying = FALSE;
1286                             player->landing = FALSE;
1287                         }
1288                     }
1289                 }
1290 
1291                 /* wall climbing - begin */
1292                 if(!floor && !brick_up) {
1293                     if((brick_left && brick_left->brick_ref->angle%90==0) || (brick_right && brick_right->brick_ref->angle%90==0)) {
1294                         player->climbing = TRUE;
1295                         player->flying = FALSE;
1296                         sound_play( soundfactory_get("touch the ground") );
1297                     }
1298                 }
1299             }
1300 
1301 
1302             /* no more landing */
1303             if(player->landing) {
1304                 if(fabs(act->speed.x) < EPSILON || !brick_down)
1305                     player->flying = player->landing = FALSE;
1306             }
1307 
1308 
1309             /* wall climbing */
1310             if(player->climbing) {
1311                 v2d_t pre_ds = v2d_new(0,0);
1312                 act->speed.x = ds.x = 0;
1313                 if(brick_left && !brick_right) act->mirror |= IF_HFLIP;
1314                 if(brick_right && !brick_left) act->mirror &= ~IF_HFLIP;
1315 
1316                 /* climbing a moving brick */
1317                 pre_ds = v2d_add(pre_ds, v2d_multiply(level_brick_move_actor(brick_left, act), dt));
1318                 pre_ds = v2d_add(pre_ds, v2d_multiply(level_brick_move_actor(brick_right, act), dt));
1319                 if((pre_ds.y <= 0 && !brick_up) || (pre_ds.y >= 0 && !brick_down) || (!brick_left && brick_right))
1320                     ds = v2d_add(ds, pre_ds);
1321 
1322                 /* climbing... */
1323                 if(brick_left || brick_right) {
1324 
1325                     /* knuckles doesn't want to climb the wall anymore */
1326                     if(input_button_pressed(act->input, IB_FIRE1)) {
1327                         animation_t *an_a = sprite_get_animation(sprite_id, 17);
1328                         animation_t *an_b = sprite_get_animation(sprite_id, 22);
1329                         if(act->animation == an_a || act->animation == an_b) { /* no wall kicking */
1330                             player->climbing = FALSE;
1331                             act->is_jumping = TRUE;
1332                             player->is_fire_jumping = TRUE;
1333                             act->speed.x = ((act->mirror&IF_HFLIP)?1:-1)*0.7*act->jump_strength;
1334                             act->speed.y = -0.5*act->jump_strength;
1335                             if(brick_left && !brick_right) act->mirror &= ~IF_HFLIP;
1336                             if(!brick_left && brick_right) act->mirror |= IF_HFLIP;
1337                             animation = sprite_get_animation(sprite_id, 3);
1338                             sound_play( soundfactory_get("jump") );
1339                         }
1340                     }
1341                     else {
1342                         /* up or down? */
1343                         if(input_button_down(act->input, IB_UP)) {
1344                             if(!brick_up) {
1345                                 ds.y = (-maxspeed*0.1) * dt;
1346                                 animation = sprite_get_animation(sprite_id, 17);
1347                             }
1348                         }
1349                         else if(input_button_down(act->input, IB_DOWN)) {
1350                             if(!brick_down) {
1351                                 ds.y = (maxspeed*0.1) * dt;
1352                                 animation = sprite_get_animation(sprite_id, 17);
1353                             }
1354                             else
1355                                 player->climbing = FALSE; /* reached the ground */
1356                         }
1357                         else
1358                             animation = sprite_get_animation(sprite_id, 22);
1359                     }
1360                 }
1361 
1362                 /* end of wall climbing */
1363                 else {
1364                     brick_tmp = (act->mirror&IF_HFLIP) ? brick_downleft : brick_downright;
1365                     if(brick_tmp) {
1366                         animation = sprite_get_animation(sprite_id, 23);
1367                         act->ignore_horizontal = TRUE;
1368                         ds = v2d_add(ds, v2d_multiply(level_brick_move_actor(brick_tmp, act), dt));
1369                         if(actor_animation_finished(act)) {
1370                             player->climbing = FALSE;
1371                             act->ignore_horizontal = FALSE;
1372                             act->speed = v2d_new(((act->mirror&IF_HFLIP)?-1:1)*maxspeed*0.15, -level_gravity()/12.5);
1373                             ds.x = ((act->mirror&IF_HFLIP)?-1:1)*5;
1374                         }
1375                     }
1376                     else {
1377                         player->climbing = FALSE;
1378                         act->is_jumping = TRUE;
1379                         animation = sprite_get_animation(sprite_id, 3);
1380                     }
1381                 }
1382 
1383 
1384             }
1385             break;
1386     }
1387 
1388 
1389     /* almost done... */
1390     player->at_some_border = FALSE;
1391     if(animation) actor_change_animation(act, animation);
1392     if(fabs(act->speed.x) < 4) {
1393         player->braking = FALSE;
1394         if( (!input_button_down(act->input, IB_RIGHT) && !input_button_down(act->input, IB_LEFT)) || (input_button_down(act->input, IB_RIGHT) && input_button_down(act->input, IB_LEFT)) || player->spin || player->landing ) {
1395             ds.x = 0;
1396             act->speed.x = 0;
1397         }
1398     }
1399     ds.x += level_brick_move_actor(brick_down,act).x*dt; /* moveable platforms II */
1400     ds.x = ((act->position.x<=act->hot_spot.x) && act->speed.x<0) ? 0 : ds.x;
1401     ds.x = ((act->position.x>=level_size().x - (actor_image(act)->w-act->hot_spot.x)) && act->speed.x>0) ? 0 : ds.x;
1402     return ds;
1403 }
1404 
1405 
1406 /*
1407  * player_bounce()
1408  * Bounces
1409  */
player_bounce(player_t * player)1410 void player_bounce(player_t *player)
1411 {
1412     input_simulate_button_down(player->actor->input, IB_FIRE1);
1413     player->spring = FALSE;
1414     player->actor->speed.y = -player->actor->jump_strength;
1415     player->actor->is_jumping = TRUE;
1416     player->is_fire_jumping = FALSE;
1417     player->flying = FALSE;
1418 }
1419 
1420 
1421 /*
1422  * player_get_rings()
1423  * Returns the amount of rings
1424  * the player has got so far
1425  */
player_get_rings()1426 int player_get_rings()
1427 {
1428     return rings;
1429 }
1430 
1431 
1432 
1433 /*
1434  * player_set_rings()
1435  * Sets a new amount of rings
1436  */
player_set_rings(int r)1437 void player_set_rings(int r)
1438 {
1439     rings = clip(r, 0, 9999);
1440 
1441     /* (100+) * k rings (k integer) = new life! */
1442     if(r/100 > hundred_rings) {
1443         hundred_rings = r/100;
1444         player_set_lives( player_get_lives()+1 );
1445         level_override_music( soundfactory_get("1up") );
1446     }
1447 }
1448 
1449 
1450 
1451 /*
1452  * player_get_lives()
1453  * How many lives does the player have?
1454  */
player_get_lives()1455 int player_get_lives()
1456 {
1457     return lives;
1458 }
1459 
1460 
1461 
1462 /*
1463  * player_set_lives()
1464  * Sets the number of lives
1465  */
player_set_lives(int l)1466 void player_set_lives(int l)
1467 {
1468     lives = max(0, l);
1469 }
1470 
1471 
1472 
1473 /*
1474  * player_get_score()
1475  * Returns the score
1476  */
player_get_score()1477 int player_get_score()
1478 {
1479     return score;
1480 }
1481 
1482 
1483 
1484 /*
1485  * player_set_score()
1486  * Sets the score
1487  */
player_set_score(int s)1488 void player_set_score(int s)
1489 {
1490     score = max(0, s);
1491 }
1492 
1493 
1494 
1495 
1496 
1497 /*
1498  * player_hit()
1499  * Hits a player. If it has no rings, then
1500  * it must die
1501  */
player_hit(player_t * player)1502 void player_hit(player_t *player)
1503 {
1504     actor_t *act = player->actor;
1505     item_t *ring;
1506     int i;
1507     int get_hit = FALSE;
1508 
1509     if(!player->blinking && !player->dying && !player->invincible) {
1510         drop_glasses(player);
1511         if(player->shield_type != SH_NONE) {
1512             /* lose shield */
1513             get_hit = TRUE;
1514             player->shield_type = SH_NONE;
1515             sound_play( soundfactory_get("death") );
1516         }
1517         else if(rings > 0) {
1518             /* lose rings */
1519             get_hit = TRUE;
1520             for(i=0; i<min(player_get_rings(), 30); i++) {
1521                 ring = level_create_item(IT_RING, act->position);
1522                 ring_start_bouncing(ring);
1523             }
1524             player_set_rings(0);
1525             sound_play( soundfactory_get("ringless") );
1526         }
1527         else {
1528             /* death */
1529             player_kill(player);
1530         }
1531     }
1532 
1533     if(get_hit) {
1534         player->getting_hit = TRUE;
1535         player->flying = player->landing = player->climbing = player->spring = FALSE;
1536         player->is_fire_jumping = FALSE;
1537         player->spin_dash = player->spin = FALSE;
1538         player->blinking = TRUE;
1539         player->blink_timer = 0;
1540         act->speed.x = act->mirror&IF_HFLIP ? 200 : -200;
1541         act->speed.y = -act->jump_strength*0.75;
1542         actor_move(act, v2d_new(0, -5));
1543     }
1544 }
1545 
1546 
1547 
1548 /*
1549  * player_kill()
1550  * Kills a player
1551  */
player_kill(player_t * player)1552 void player_kill(player_t *player)
1553 {
1554     if(!player->dying) {
1555         drop_glasses(player);
1556         player->shield_type = SH_NONE;
1557         player->invincible = FALSE;
1558         player->got_speedshoes = FALSE;
1559         player->dying = TRUE;
1560         player->death_timer = 0;
1561         player->spring = FALSE;
1562         player->actor->speed.y = -player->actor->jump_strength*1.2;
1563         player->flying = player->climbing = player->landing = FALSE;
1564         player->is_fire_jumping = FALSE;
1565         player->spin = player->spin_dash = FALSE;
1566         player->blinking = FALSE;
1567         sound_play( soundfactory_get("death") );
1568     }
1569 }
1570 
1571 
1572 
1573 /*
1574  * player_attacking()
1575  * Returns TRUE if a given player is attacking;
1576  * FALSE otherwise
1577  */
player_attacking(player_t * player)1578 int player_attacking(player_t *player)
1579 {
1580     animation_t *jump = sprite_get_animation(get_sprite_id(player->type), 3);
1581     return player->spin || player->spin_dash ||
1582            (/*player->actor->is_jumping &&*/ player->actor->animation == jump) ||
1583            (player->type == PL_KNUCKLES && (player->landing || player->flying));
1584 }
1585 
1586 
1587 /*
1588  * player_get_sprite_name()
1589  * Returns the name of the sprite used by the player
1590  */
player_get_sprite_name(player_t * player)1591 const char *player_get_sprite_name(player_t *player)
1592 {
1593     return get_sprite_id(player->type);
1594 }
1595 
1596 
1597 
1598 /* private functions */
get_sprite_id(int player_type)1599 const char *get_sprite_id(int player_type)
1600 {
1601     switch(player_type) {
1602         case PL_SONIC:
1603             return "SD_SONIC";
1604 
1605         case PL_TAILS:
1606             return "SD_TAILS";
1607 
1608         case PL_KNUCKLES:
1609             return "SD_KNUCKLES";
1610 
1611         default:
1612             return "null";
1613     }
1614 }
1615 
1616 
update_glasses(player_t * p)1617 void update_glasses(player_t *p)
1618 {
1619     int frame_id = 0, hflip = p->actor->mirror & IF_HFLIP;
1620     int visible = TRUE;
1621     float ang = old_school_angle(p->actor->angle);
1622     v2d_t gpos = v2d_new(0,0);
1623     v2d_t top = v2d_subtract(p->actor->position,v2d_rotate(v2d_new(0,p->actor->hot_spot.y),-ang));
1624     animation_t *anim = p->actor->animation;
1625 
1626 
1627 
1628     switch(p->type) {
1629 
1630 
1631         case PL_SONIC:
1632             if(anim == sprite_get_animation(get_sprite_id(PL_SONIC), 0)) {
1633                 /* stopped */
1634                 gpos = v2d_new(3,24);
1635                 frame_id = 1;
1636             }
1637             else if(anim == sprite_get_animation(get_sprite_id(PL_SONIC), 1)) {
1638                 /* walking */
1639                 switch((int)p->actor->animation_frame) {
1640                     case 0: frame_id = 2; gpos = v2d_new(5,23); break;
1641                     case 1: frame_id = 2; gpos = v2d_new(4,25); break;
1642                     case 2: frame_id = 1; gpos = v2d_new(7,25); break;
1643                     case 3: frame_id = 1; gpos = v2d_new(5,23); break;
1644                     case 4: frame_id = 1; gpos = v2d_new(5,23); break;
1645                     case 5: frame_id = 1; gpos = v2d_new(4,24); break;
1646                     case 6: frame_id = 2; gpos = v2d_new(6,24); break;
1647                     case 7: frame_id = 2; gpos = v2d_new(6,23); break;
1648                 }
1649             }
1650             else if(anim == sprite_get_animation(get_sprite_id(PL_SONIC), 2)) {
1651                 /* running */
1652                 frame_id = 1;
1653                 gpos = v2d_new(8,26);
1654             }
1655             else if(anim == sprite_get_animation(get_sprite_id(PL_SONIC), 5)) {
1656                 /* look up */
1657                 frame_id = 3;
1658                 if((int)p->actor->animation_frame == 0)
1659                     gpos = v2d_new(0,19);
1660                 else
1661                     gpos = v2d_new(-1,21);
1662             }
1663             else if(anim == sprite_get_animation(get_sprite_id(PL_SONIC), 7)) {
1664                 /* braking */
1665                 frame_id = 1;
1666                 if((int)p->actor->animation_frame < 2)
1667                     gpos = v2d_new(8,26);
1668                 else
1669                     gpos = v2d_new(10,28);
1670             }
1671             else if(anim == sprite_get_animation(get_sprite_id(PL_SONIC), 10)) {
1672                 /* almost falling / ledge */
1673                 frame_id = 1;
1674                 switch((int)p->actor->animation_frame) {
1675                     case 0: gpos = v2d_new(1,22); break;
1676                     case 1: gpos = v2d_new(-1,23); break;
1677                     case 2: gpos = v2d_new(1,23); break;
1678                 }
1679             }
1680             else if(anim == sprite_get_animation(get_sprite_id(PL_SONIC), 11)) {
1681                 /* ringless */
1682                 frame_id = 3;
1683                 gpos = v2d_new(-4,30);
1684             }
1685             else if(anim == sprite_get_animation(get_sprite_id(PL_SONIC), 12)) {
1686                 /* breathing */
1687                 frame_id = 3;
1688                 gpos = v2d_new(1,19);
1689             }
1690             else if(anim == sprite_get_animation(get_sprite_id(PL_SONIC), 13)) {
1691                 /* spring */
1692                 frame_id = 3;
1693                 gpos = v2d_new(4,13);
1694             }
1695             else if(anim == sprite_get_animation(get_sprite_id(PL_SONIC), 14)) {
1696                 /* pushing */
1697                 frame_id = 1;
1698                 gpos = v2d_new(12,31);
1699             }
1700             else if(anim == sprite_get_animation(get_sprite_id(PL_SONIC), 15)) {
1701                 /* waiting */
1702                 frame_id = 0;
1703                 gpos = v2d_new(3,23);
1704             }
1705             else if(anim == sprite_get_animation(get_sprite_id(PL_SONIC), 25)) {
1706                 /* being carried */
1707                 frame_id = 0;
1708                 gpos = v2d_new(3,22);
1709             }
1710             else
1711                 visible = FALSE;
1712             break;
1713 
1714 
1715 
1716         case PL_TAILS:
1717             if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 0)) {
1718                 /* stopped */
1719                 gpos = v2d_new(5,34);
1720                 frame_id = 1;
1721             }
1722             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 1)) {
1723                 /* walking */
1724                 frame_id = 2;
1725                 switch((int)p->actor->animation_frame) {
1726                     case 0: gpos = v2d_new(2,33); break;
1727                     case 1: gpos = v2d_new(3,33); break;
1728                     case 2: gpos = v2d_new(8,33); break;
1729                     case 3: gpos = v2d_new(3,32); break;
1730                     case 4: gpos = v2d_new(1,33); break;
1731                     case 5: gpos = v2d_new(3,33); break;
1732                     case 6: gpos = v2d_new(7,33); break;
1733                     case 7: gpos = v2d_new(3,32); break;
1734                 }
1735             }
1736             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 2)) {
1737                 /* running */
1738                 frame_id = 2;
1739                 if((int)p->actor->animation_frame == 0)
1740                     gpos = v2d_new(7,35);
1741                 else
1742                     gpos = v2d_new(6,34);
1743             }
1744             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 4)) {
1745                 /* crouch down */
1746                 frame_id = 1;
1747                 gpos = v2d_new(9,44);
1748             }
1749             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 5)) {
1750                 /* look up */
1751                 frame_id = 1;
1752                 gpos = v2d_new(7,32);
1753             }
1754             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 7)) {
1755                 /* braking */
1756                 frame_id = 1;
1757                 if((int)p->actor->animation_frame == 0)
1758                     gpos = v2d_new(2,33);
1759                 else
1760                     gpos = v2d_new(4,33);
1761             }
1762             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 10)) {
1763                 /* almost falling / ledge */
1764                 frame_id = 4;
1765                 switch((int)p->actor->animation_frame) {
1766                     case 0: gpos = v2d_new(5,33); break;
1767                     case 1: gpos = v2d_new(6,33); break;
1768                 }
1769             }
1770             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 11)) {
1771                 /* ringless */
1772                 frame_id = 1;
1773                 gpos = v2d_new(1,33);
1774             }
1775             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 12)) {
1776                 /* breathing */
1777                 frame_id = 1;
1778                 gpos = v2d_new(6,28);
1779             }
1780             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 13)) {
1781                 /* spring */
1782                 frame_id = 3;
1783                 gpos = v2d_new(2,17);
1784             }
1785             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 14)) {
1786                 /* pushing */
1787                 frame_id = 1;
1788                 gpos = v2d_new(9,35);
1789             }
1790             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 15)) {
1791                 /* waiting */
1792                 frame_id = 4;
1793                 switch((int)p->actor->animation_frame) {
1794                     case 0: case 8: case 9: case 10: gpos = v2d_new(5,34); break;
1795                     default: gpos = v2d_new(5,33); break;
1796                 }
1797             }
1798             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 16)) {
1799                 /* carrying */
1800                 frame_id = 1;
1801                 gpos = v2d_new(8,37);
1802             }
1803             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 19)) {
1804                 /* tired of flying */
1805                 frame_id = 1;
1806                 if((int)p->actor->animation_frame == 0)
1807                     gpos = v2d_new(9,39);
1808                 else
1809                     gpos = v2d_new(9,40);
1810             }
1811             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 20)) {
1812                 /* flying */
1813                 frame_id = 1;
1814                 gpos = v2d_new(8,39);
1815             }
1816             else if(anim == sprite_get_animation(get_sprite_id(PL_TAILS), 25)) {
1817                 /* being carried */
1818                 frame_id = 1;
1819                 gpos = v2d_new(0,23);
1820             }
1821             else
1822                 visible = FALSE;
1823             break;
1824 
1825 
1826         case PL_KNUCKLES:
1827             if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 0)) {
1828                 /* stopped */
1829                 frame_id = 1;
1830                 gpos = v2d_new(1,24);
1831             }
1832             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 1)) {
1833                 /* walking */
1834                 switch((int)p->actor->animation_frame) {
1835                     case 0: frame_id = 1; gpos = v2d_new(5,29); break;
1836                     case 1: frame_id = 2; gpos = v2d_new(5,29); break;
1837                     case 2: frame_id = 2; gpos = v2d_new(8,29); break;
1838                     case 3: frame_id = 2; gpos = v2d_new(9,28); break;
1839                     case 4: frame_id = 1; gpos = v2d_new(6,28); break;
1840                     case 5: frame_id = 1; gpos = v2d_new(6,29); break;
1841                     case 6: frame_id = 1; gpos = v2d_new(5,28); break;
1842                     case 7: frame_id = 1; gpos = v2d_new(4,27); break;
1843                 }
1844             }
1845             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 2)) {
1846                 /* running */
1847                 frame_id = 1;
1848                 gpos = v2d_new(7,29);
1849             }
1850             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 4)) {
1851                 /* crouch down */
1852                 frame_id = 1;
1853                 if((int)p->actor->animation_frame == 0)
1854                     gpos = v2d_new(0,31);
1855                 else
1856                     gpos = v2d_new(0,40);
1857             }
1858             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 5)) {
1859                 /* look up */
1860                 frame_id = 1;
1861                 if((int)p->actor->animation_frame == 0)
1862                     gpos = v2d_new(0,21);
1863                 else
1864                     gpos = v2d_new(-1,21);
1865             }
1866             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 7)) {
1867                 /* braking */
1868                 frame_id = 0;
1869                 gpos = v2d_new(-2,27);
1870             }
1871             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 10)) {
1872                 /* almost falling / ledge */
1873                 frame_id = 1;
1874                 switch((int)p->actor->animation_frame) {
1875                     case 0: gpos = v2d_new(9,30); break;
1876                     case 1: gpos = v2d_new(8,27); break;
1877                 }
1878             }
1879             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 11)) {
1880                 /* ringless */
1881                 frame_id = 1;
1882                 gpos = v2d_new(-3,27);
1883             }
1884             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 12)) {
1885                 /* breathing */
1886                 frame_id = 1;
1887                 gpos = v2d_new(5,24);
1888             }
1889             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 13)) {
1890                 /* spring */
1891                 frame_id = 3;
1892                 gpos = v2d_new(-1,16);
1893             }
1894             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 14)) {
1895                 /* pushing */
1896                 switch((int)p->actor->animation_frame) {
1897                     case 0: frame_id = 1; gpos = v2d_new(5,29); break;
1898                     case 1: frame_id = 2; gpos = v2d_new(5,29); break;
1899                     case 2: frame_id = 2; gpos = v2d_new(8,29); break;
1900                     case 3: frame_id = 2; gpos = v2d_new(9,28); break;
1901                     case 4: frame_id = 1; gpos = v2d_new(6,28); break;
1902                     case 5: frame_id = 1; gpos = v2d_new(6,29); break;
1903                     case 6: frame_id = 1; gpos = v2d_new(5,28); break;
1904                     case 7: frame_id = 1; gpos = v2d_new(4,27); break;
1905                 }
1906             }
1907             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 15)) {
1908                 /* waiting */
1909                 frame_id = 0;
1910                 gpos = v2d_new(1,23);
1911             }
1912             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 16)) {
1913                 /* no more climbing */
1914                 frame_id = 1;
1915                 switch((int)p->actor->animation_frame) {
1916                     case 0: gpos = v2d_new(6,23); break;
1917                     case 1: gpos = v2d_new(5,20); break;
1918                     case 2: gpos = v2d_new(0,22); break;
1919                 }
1920             }
1921             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 17)) {
1922                 /* climbing */
1923                 frame_id = 3;
1924                 switch((int)p->actor->animation_frame) {
1925                     case 0: gpos = v2d_new(-1,22); break;
1926                     case 1: gpos = v2d_new(-2,20); break;
1927                     case 2: gpos = v2d_new(0,21); break;
1928                     case 3: gpos = v2d_new(-1,24); break;
1929                     case 4: gpos = v2d_new(0,23); break;
1930                     case 5: gpos = v2d_new(0,22); break;
1931                 }
1932             }
1933             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 18)) {
1934                 /* end of flight */
1935                 frame_id = 1;
1936                 if((int)p->actor->animation_frame == 0)
1937                     gpos = v2d_new(6,23);
1938                 else
1939                     gpos = v2d_new(5,20);
1940             }
1941             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 19)) {
1942                 /* flying - ground */
1943                 frame_id = 1;
1944                 gpos = v2d_new(8,44);
1945             }
1946             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 20)) {
1947                 /* flying - air */
1948                 frame_id = 1;
1949                 gpos = v2d_new(8,39);
1950             }
1951             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 21)) {
1952                 /* flying - turn */
1953                 frame_id = 4;
1954                 switch((int)p->actor->animation_frame) {
1955                     case 0: gpos = v2d_new(-8,41); break;
1956                     case 1: gpos = v2d_new(0,43); break;
1957                     case 2: gpos = v2d_new(10,41); break;
1958                 }
1959             }
1960             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 22)) {
1961                 /* climbing - stopped */
1962                 frame_id = 3;
1963                 gpos = v2d_new(0,22);
1964             }
1965             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 23)) {
1966                 /* climbing - reached the top */
1967                 switch((int)p->actor->animation_frame) {
1968                     case 0: frame_id = 3; gpos = v2d_new(7,17); break;
1969                     case 1: frame_id = 3; gpos = v2d_new(11,15); break;
1970                     case 2: frame_id = 0; gpos = v2d_new(12,13); break;
1971                 }
1972             }
1973             else if(anim == sprite_get_animation(get_sprite_id(PL_KNUCKLES), 25)) {
1974                 /* being carried */
1975                 frame_id = 0;
1976                 gpos = v2d_new(0,23);
1977             }
1978             else
1979                 visible = FALSE;
1980             break;
1981     }
1982 
1983     gpos.x *= hflip ? -1 : 1;
1984     actor_change_animation(p->glasses, sprite_get_animation("SD_GLASSES", frame_id));
1985     p->glasses->position = v2d_add(top, v2d_rotate(gpos, -ang));
1986     p->glasses->angle = ang;
1987     p->glasses->mirror = p->actor->mirror;
1988     p->glasses->visible = visible && p->actor->visible;
1989 }
1990 
1991 
1992 
drop_glasses(player_t * p)1993 void drop_glasses(player_t *p)
1994 {
1995     if(p->got_glasses) {
1996         v2d_t pos = v2d_add(p->actor->position, v2d_new(0,-27));
1997         item_t *item = level_create_item(IT_FALGLASSES, pos);
1998         falglasses_set_speed(item, v2d_new(-0.2f * p->actor->speed.x, -490.0f));
1999         p->got_glasses = FALSE;
2000     }
2001 }
2002 
2003 
2004 
update_shield(player_t * p)2005 void update_shield(player_t *p)
2006 {
2007     actor_t *sh = p->shield, *act = p->actor;
2008     v2d_t off = v2d_new(0,0);
2009 
2010     switch(p->shield_type) {
2011 
2012         case SH_SHIELD:
2013             off = v2d_new(0,-22);
2014             sh->position = v2d_add(act->position, v2d_rotate(off, -old_school_angle(act->angle)));
2015             actor_change_animation(sh, sprite_get_animation("SD_SHIELD", 0));
2016             break;
2017 
2018         case SH_FIRESHIELD:
2019             off = v2d_new(0,-22);
2020             sh->position = v2d_add(act->position, v2d_rotate(off, -old_school_angle(act->angle)));
2021             actor_change_animation(sh, sprite_get_animation("SD_FIRESHIELD", 0));
2022             break;
2023 
2024         case SH_THUNDERSHIELD:
2025             off = v2d_new(0,-22);
2026             sh->position = v2d_add(act->position, v2d_rotate(off, -old_school_angle(act->angle)));
2027             actor_change_animation(sh, sprite_get_animation("SD_THUNDERSHIELD", 0));
2028             break;
2029 
2030         case SH_WATERSHIELD:
2031             off = v2d_new(0,-22);
2032             sh->position = v2d_add(act->position, v2d_rotate(off, -old_school_angle(act->angle)));
2033             actor_change_animation(sh, sprite_get_animation("SD_WATERSHIELD", 0));
2034             break;
2035 
2036         case SH_ACIDSHIELD:
2037             off = v2d_new(0,-22);
2038             sh->position = v2d_add(act->position, v2d_rotate(off, -old_school_angle(act->angle)));
2039             actor_change_animation(sh, sprite_get_animation("SD_ACIDSHIELD", 0));
2040             break;
2041 
2042         case SH_WINDSHIELD:
2043             off = v2d_new(0,-22);
2044             sh->position = v2d_add(act->position, v2d_rotate(off, -old_school_angle(act->angle)));
2045             actor_change_animation(sh, sprite_get_animation("SD_WINDSHIELD", 0));
2046             break;
2047     }
2048 }
2049 
2050 
2051 /* is the player inside a loop? */
inside_loop(player_t * p)2052 int inside_loop(player_t *p)
2053 {
2054     return (p->disable_wall != PLAYER_WALL_NONE);
2055 }
2056 
2057 /* the player won't leave the floor unless necessary */
stickyphysics_hack(player_t * player,brick_list_t * brick_list,brick_t ** brick_downleft,brick_t ** brick_down,brick_t ** brick_downright)2058 void stickyphysics_hack(player_t *player, brick_list_t *brick_list, brick_t **brick_downleft, brick_t **brick_down, brick_t **brick_downright)
2059 {
2060     actor_t *act = player->actor;
2061     float oldy = act->position.y;
2062 
2063     if(NULL == *brick_down && !act->is_jumping && !player->is_fire_jumping && !player->flying && !player->climbing && !player->landing && !player->spring && !player->getting_hit && !player->dead && !player->dying) {
2064         int i;
2065         float sqrsize=2, diff=-2;
2066         brick_t *downleft, *down, *downright;
2067         for(i=0; i<8; i++) {
2068             act->position.y = oldy + (float)(1+i);
2069             actor_corners(act, sqrsize, diff, brick_list, NULL, NULL, NULL, &downright, &down, &downleft, NULL, NULL);
2070             if(NULL != down) {
2071                 *brick_downleft = downleft;
2072                 *brick_down = down;
2073                 *brick_downright = downright;
2074                 return;
2075             }
2076         }
2077     }
2078 
2079     act->position.y = oldy;
2080 }
2081 
2082 /* aaaargh!! the player is being crushed! */
got_crushed(player_t * p,brick_t * brick_up,brick_t * brick_right,brick_t * brick_down,brick_t * brick_left)2083 int got_crushed(player_t *p, brick_t *brick_up, brick_t *brick_right, brick_t *brick_down, brick_t *brick_left)
2084 {
2085     float sx, sy, t;
2086 
2087     if(p->climbing)
2088         return FALSE;
2089 
2090     /* y-axis */
2091     if(brick_up && brick_down && brick_up != brick_down) {
2092         if(brick_up->brick_ref->behavior == BRB_CIRCULAR && brick_up->brick_ref->property == BRK_OBSTACLE) {
2093             t = brick_up->value[0];
2094             sy = brick_up->brick_ref->behavior_arg[3];
2095             if(sin(sy * t) > 0) return TRUE; /* crushed! */
2096         }
2097 
2098         if(brick_down->brick_ref->behavior == BRB_CIRCULAR && brick_down->brick_ref->property == BRK_OBSTACLE) {
2099             t = brick_down->value[0];
2100             sy = brick_down->brick_ref->behavior_arg[3];
2101             if(sin(sy * t) < 0) return TRUE; /* crushed! */
2102         }
2103     }
2104 
2105     /* x-axis */
2106     if(brick_left && brick_right && brick_left != brick_right) {
2107         if(brick_left->brick_ref->behavior == BRB_CIRCULAR && brick_left->brick_ref->property == BRK_OBSTACLE) {
2108             t = brick_left->value[0];
2109             sx = brick_left->brick_ref->behavior_arg[2];
2110             if(cos(sx * t) > 0) return TRUE; /* crushed! */
2111         }
2112 
2113         if(brick_right->brick_ref->behavior == BRB_CIRCULAR && brick_right->brick_ref->property == BRK_OBSTACLE) {
2114             t = brick_right->value[0];
2115             sx = brick_right->brick_ref->behavior_arg[2];
2116             if(cos(sx * t) < 0) return TRUE; /* crushed! */
2117         }
2118     }
2119 
2120     /* I'm not being crushed */
2121     return FALSE;
2122 }
2123