- moved time_left timer into gamesession
[supertux.git] / src / player.cpp
1 //
2 // C Implementation: player/tux
3 //
4 // Description:
5 //
6 //
7 // Author: Tobias Glaesser <tobi.web@gmx.de> & Bill Kendrick, (C) 2004
8 //
9 // Copyright: See COPYING file that comes with this distribution
10 //
11 //
12 #include <math.h>
13
14 #include "gameloop.h"
15 #include "globals.h"
16 #include "player.h"
17 #include "defines.h"
18 #include "scene.h"
19 #include "tile.h"
20 #include "screen.h"
21
22 texture_type tux_life;
23 std::vector<texture_type> tux_right;
24 std::vector<texture_type> tux_left;
25 texture_type smalltux_jump_left;
26 texture_type smalltux_jump_right;
27 texture_type smalltux_stand_left;
28 texture_type smalltux_stand_right;
29
30 texture_type bigtux_right[3];
31 texture_type bigtux_left[3];
32 texture_type bigtux_right_jump;
33 texture_type bigtux_left_jump;
34 texture_type ducktux_right;
35 texture_type ducktux_left;
36 texture_type skidtux_right;
37 texture_type skidtux_left;
38 texture_type firetux_right[3];
39 texture_type firetux_left[3];
40 texture_type bigfiretux_right[3];
41 texture_type bigfiretux_left[3];
42 texture_type bigfiretux_right_jump;
43 texture_type bigfiretux_left_jump;
44 texture_type duckfiretux_right;
45 texture_type duckfiretux_left;
46 texture_type skidfiretux_right;
47 texture_type skidfiretux_left;
48 texture_type cape_right[2];
49 texture_type cape_left[2];
50 texture_type bigcape_right[2];
51 texture_type bigcape_left[2];
52
53 void player_input_init(player_input_type* pplayer_input)
54 {
55   pplayer_input->down = UP;
56   pplayer_input->fire = UP;
57   pplayer_input->left = UP;
58   pplayer_input->old_fire = UP;
59   pplayer_input->right = UP;
60   pplayer_input->up = UP;
61 }
62
63 void
64 Player::init()
65 {
66   base.width = 32;
67   base.height = 32;
68
69   size = SMALL;
70   got_coffee = false;
71
72   // FIXME: Make the start position configurable via the levelfile
73   base.x = 100;
74   base.y = 240;
75   base.xm = 0;
76   base.ym = 0;
77   old_base = base;
78   dir = RIGHT;
79   duck = false;
80
81   dying   = DYING_NOT;
82   jumping = false;
83
84   frame_main = 0;
85   frame_ = 0;
86   lives = 3;
87   score = 0;
88   distros = 0;
89
90   player_input_init(&input);
91
92   keymap.jump  = SDLK_UP;
93   keymap.duck  = SDLK_DOWN;
94   keymap.left  = SDLK_LEFT;
95   keymap.right = SDLK_RIGHT;
96   keymap.fire  = SDLK_LCTRL;
97
98   timer_init(&invincible_timer,true);
99   timer_init(&skidding_timer,true);
100   timer_init(&safe_timer,true);
101   timer_init(&frame_timer,true);
102
103   physic.reset();
104 }
105
106 int
107 Player::key_event(SDLKey key, int state)
108 {
109   if(key == keymap.right)
110     {
111       input.right = state;
112       return true;
113     }
114   else if(key == keymap.left)
115     {
116       input.left = state;
117       return true;
118     }
119   else if(key == keymap.jump)
120     {
121       input.up = state;
122       return true;
123     }
124   else if(key == keymap.duck)
125     {
126       input.down = state;
127       return true;
128     }
129   else if(key == keymap.fire)
130     {
131       input.fire = state;
132       return true;
133     }
134   else
135     return false;
136 }
137
138 void
139 Player::level_begin()
140 {
141   base.x  = 100;
142   base.y  = 240;
143   base.xm = 0;
144   base.ym = 0;
145   old_base = base;
146   previous_base = base;
147
148   dying = DYING_NOT;
149
150   player_input_init(&input);
151
152   timer_init(&invincible_timer,true);
153   timer_init(&skidding_timer,true);
154   timer_init(&safe_timer,true);
155   timer_init(&frame_timer,true);
156   physic.reset();
157 }
158
159 void
160 Player::action(double frame_ratio)
161 {
162   bool jumped_in_solid = false;
163
164   /* --- HANDLE TUX! --- */
165
166   if(!dying)
167     handle_input();
168
169   /* Move tux: */
170   previous_base = base;
171
172   physic.apply(frame_ratio, base.x, base.y);
173
174   if (!dying)
175     {
176
177       collision_swept_object_map(&old_base,&base);
178       keep_in_bounds();
179
180       /* Land: */
181
182
183       if( !on_ground())
184         {
185           physic.enable_gravity(true);
186           if(under_solid())
187             {
188               // fall down
189               physic.set_velocity(physic.get_velocity_x(), 0);
190               jumped_in_solid = true;
191             }
192         }
193       else
194         {
195           /* Land: */
196           if (physic.get_velocity_y() < 0)
197             {
198               base.y = (int)(((int)base.y / 32) * 32);
199               physic.set_velocity(physic.get_velocity_x(), 0);
200             }
201
202           physic.enable_gravity(false);
203           /* Reset score multiplier (for multi-hits): */
204           player_status.score_multiplier = 1;
205         }
206
207       if(jumped_in_solid)
208         {
209           if (isbrick(base.x, base.y) ||
210               isfullbox(base.x, base.y))
211             {
212               World::current()->trygrabdistro(base.x, base.y - 32,BOUNCE);
213               World::current()->trybumpbadguy(base.x, base.y - 64);
214
215               World::current()->trybreakbrick(base.x, base.y, size == SMALL);
216
217               bumpbrick(base.x, base.y);
218               World::current()->tryemptybox(base.x, base.y, RIGHT);
219             }
220
221           if (isbrick(base.x+ 31, base.y) ||
222               isfullbox(base.x+ 31, base.y))
223             {
224               World::current()->trygrabdistro(base.x+ 31, base.y - 32,BOUNCE);
225               World::current()->trybumpbadguy(base.x+ 31, base.y - 64);
226
227               if(size == BIG)
228                 World::current()->trybreakbrick(base.x+ 31, base.y, size == SMALL);
229
230               bumpbrick(base.x+ 31, base.y);
231               World::current()->tryemptybox(base.x+ 31, base.y, LEFT);
232             }
233         }
234
235       grabdistros();
236
237       if (jumped_in_solid)
238         {
239           ++base.y;
240           ++old_base.y;
241           if(on_ground())
242             {
243               /* Make sure jumping is off. */
244               jumping = false;
245             }
246         }
247
248     }
249
250   timer_check(&safe_timer);
251
252
253   /* ---- DONE HANDLING TUX! --- */
254
255   /* Handle invincibility timer: */
256   if (get_current_music() == HERRING_MUSIC && !timer_check(&invincible_timer))
257     {
258       /*
259          no, we are no more invincible
260          or we were not in invincible mode
261          but are we in hurry ?
262        */
263
264       // FIXME: Move this to gamesession
265       if (timer_get_left(&GameSession::current()->time_left) < TIME_WARNING)
266         {
267           /* yes, we are in hurry
268              stop the herring_song, prepare to play the correct
269              fast level_song !
270            */
271           set_current_music(HURRYUP_MUSIC);
272         }
273       else
274         {
275           set_current_music(LEVEL_MUSIC);
276         }
277
278       /* start playing it */
279       play_current_music();
280     }
281
282   /* Handle skidding: */
283
284   // timer_check(&skidding_timer); // disabled
285
286   /* End of level? */
287   if (base.x >= World::current()->get_level()->endpos
288       && World::current()->get_level()->endpos != 0)
289     {
290       player_status.next_level = 1;
291     }
292
293 }
294
295 bool
296 Player::on_ground()
297 {
298   return ( issolid(base.x + base.width / 2, base.y + base.height) ||
299            issolid(base.x + 1, base.y + base.height) ||
300            issolid(base.x + base.width - 1, base.y + base.height)  );
301 }
302
303 bool
304 Player::under_solid()
305 {
306   return ( issolid(base.x + base.width / 2, base.y) ||
307            issolid(base.x + 1, base.y) ||
308            issolid(base.x + base.width - 1, base.y)  );
309 }
310
311 void
312 Player::handle_horizontal_input(int newdir)
313 {
314   if(duck)
315     return;
316
317   float vx = physic.get_velocity_x();
318   float vy = physic.get_velocity_y();
319   dir = newdir;
320
321   // skid if we're too fast
322   if(dir != newdir && on_ground() && fabs(physic.get_velocity_x()) > SKID_XM 
323           && !timer_started(&skidding_timer))
324     {
325       timer_start(&skidding_timer, SKID_TIME);
326       play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER);
327       return;
328     }
329
330   if ((newdir ? (vx < 0) : (vx > 0)) && !isice(base.x, base.y + base.height) &&
331       !timer_started(&skidding_timer))
332     {
333       //vx = 0;
334     }
335
336   /* Facing the direction we're jumping?  Go full-speed: */
337   if (input.fire == UP)
338     {
339       if(vx >= MAX_WALK_XM) {
340         vx = MAX_WALK_XM;
341         physic.set_acceleration(0, 0); // enough speedup
342       } else if(vx <= -MAX_WALK_XM) {
343         vx = -MAX_WALK_XM;
344         physic.set_acceleration(0, 0);
345       }
346       physic.set_acceleration(newdir ? 0.02 : -0.02, 0);
347       if(fabs(vx) < 1) // set some basic run speed
348         vx = newdir ? 1 : -1;
349 #if 0
350       vx += ( newdir ? WALK_SPEED : -WALK_SPEED) * frame_ratio;
351
352       if(newdir)
353         {
354           if (vx > MAX_WALK_XM)
355             vx = MAX_WALK_XM;
356         }
357       else
358         {
359           if (vx < -MAX_WALK_XM)
360             vx = -MAX_WALK_XM;
361         }
362 #endif
363     }
364   else if ( input.fire == DOWN)
365     {
366       if(vx >= MAX_RUN_XM) {
367         vx = MAX_RUN_XM;
368         physic.set_acceleration(0, 0); // enough speedup      
369       } else if(vx <= -MAX_RUN_XM) {
370         vx = -MAX_RUN_XM;
371         physic.set_acceleration(0, 0);
372       }
373       physic.set_acceleration(newdir ? 0.03 : -0.03, 0);
374       if(fabs(vx) < 1) // set some basic run speed
375         vx = newdir ? 1 : -1;
376
377 #if 0
378       vx = vx + ( newdir ? RUN_SPEED : -RUN_SPEED) * frame_ratio;
379
380       if(newdir)
381         {
382           if (vx > MAX_RUN_XM)
383             vx = MAX_RUN_XM;
384         }
385       else
386         {
387           if (vx < -MAX_RUN_XM)
388             vx = -MAX_RUN_XM;
389         }
390 #endif
391     }
392   else
393     {
394 #if 0
395       /* Not facing the direction we're jumping?
396          Go half-speed: */
397       vx = vx + ( newdir ? (WALK_SPEED / 2) : -(WALK_SPEED / 2)) * frame_ratio;
398
399       if(newdir)
400         {
401           if (vx > MAX_WALK_XM / 2)
402             vx = MAX_WALK_XM / 2;
403         }
404       else
405         {
406           if (vx < -MAX_WALK_XM / 2)
407             vx = -MAX_WALK_XM / 2;
408         }
409 #endif
410     }
411   
412   physic.set_velocity(vx, vy);
413 }
414
415 void
416 Player::handle_vertical_input()
417 {
418   if(input.up == DOWN)
419     {
420       if (on_ground())
421         {
422           // jump
423           physic.set_velocity(physic.get_velocity_x(), 5.5);
424           --base.y;
425           jumping = true;
426           if (size == SMALL)
427             play_sound(sounds[SND_JUMP], SOUND_CENTER_SPEAKER);
428           else
429             play_sound(sounds[SND_BIGJUMP], SOUND_CENTER_SPEAKER);
430         }
431     }
432   else if(input.up == UP && jumping)
433     {
434       jumping = false;
435       if(physic.get_velocity_y() > 0) {
436         physic.set_velocity(physic.get_velocity_x(), 0);
437       }
438     }
439 }
440
441 void
442 Player::handle_input()
443 {
444   /* Handle key and joystick state: */
445   if(duck == false)
446     {
447       if (input.right == DOWN && input.left == UP)
448         {
449           handle_horizontal_input(RIGHT);
450         }
451       else if (input.left == DOWN && input.right == UP)
452         {
453           handle_horizontal_input(LEFT);
454         }
455       else
456         {
457           float vx = physic.get_velocity_x();
458           if(fabs(vx) < 0.01) {
459             physic.set_velocity(0, physic.get_velocity_y());
460             physic.set_acceleration(0, 0);
461           } else if(vx < 0) {
462             physic.set_acceleration(0.1, 0);
463           } else {
464             physic.set_acceleration(-0.1, 0);
465           }
466         }
467     }
468
469   /* Jump/jumping? */
470
471   if ( input.up == DOWN || (input.up == UP && jumping))
472     {
473       handle_vertical_input();
474     }
475
476   /* Shoot! */
477
478   if (input.fire == DOWN && input.old_fire == UP && got_coffee)
479     {
480       World::current()->add_bullet(base.x, base.y, physic.get_velocity_x(), dir);
481     }
482
483
484   /* Duck! */
485
486   if (input.down == DOWN)
487     {
488       if (size == BIG && duck != true)
489         {
490           duck = true;
491           base.height = 32;
492           base.y += 32;
493         }
494     }
495   else
496     {
497       if (size == BIG && duck)
498         {
499           /* Make sure we're not standing back up into a solid! */
500           base.height = 64;
501           base.y -= 32;
502
503           if (!collision_object_map(&base) /*issolid(base.x + 16, base.y - 16)*/)
504             {
505               duck = false;
506               base.height = 64;
507               old_base.y -= 32;
508               old_base.height = 64;
509             }
510           else
511             {
512               base.height = 32;
513               base.y += 32;
514             }
515         }
516       else
517         {
518           duck = false;
519         }
520     }
521
522   /* (Tux): */
523
524   if(!timer_check(&frame_timer))
525     {
526       timer_start(&frame_timer,25);
527       if (input.right == UP && input.left == UP)
528         {
529           frame_main = 1;
530           frame_ = 1;
531         }
532       else
533         {
534           if ((input.fire == DOWN && (global_frame_counter % 2) == 0) ||
535               (global_frame_counter % 4) == 0)
536             frame_main = (frame_main + 1) % 4;
537
538           frame_ = frame_main;
539
540           if (frame_ == 3)
541             frame_ = 1;
542         }
543     }
544
545 }
546
547 void
548 Player::grabdistros()
549 {
550   /* Grab distros: */
551   if (!dying)
552     {
553       World::current()->trygrabdistro(base.x, base.y, NO_BOUNCE);
554       World::current()->trygrabdistro(base.x+ 31, base.y, NO_BOUNCE);
555
556       World::current()->trygrabdistro(base.x, base.y + base.height, NO_BOUNCE);
557       World::current()->trygrabdistro(base.x+ 31, base.y + base.height, NO_BOUNCE);
558
559       if(size == BIG)
560         {
561           World::current()->trygrabdistro(base.x, base.y + base.height / 2, NO_BOUNCE);
562           World::current()->trygrabdistro(base.x+ 31, base.y + base.height / 2, NO_BOUNCE);
563         }
564
565     }
566
567   /* Enough distros for a One-up? */
568   if (distros >= DISTROS_LIFEUP)
569     {
570       distros = distros - DISTROS_LIFEUP;
571       if(lives < MAX_LIVES)
572         lives++;
573       /*We want to hear the sound even, if MAX_LIVES is reached*/
574       play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
575     }
576 }
577
578 void
579 Player::draw()
580 {
581   if (!timer_started(&safe_timer) || (global_frame_counter % 2) == 0)
582     {
583       if (size == SMALL)
584         {
585           if (timer_started(&invincible_timer))
586             {
587               /* Draw cape: */
588
589               if (dir == RIGHT)
590                 {
591                   texture_draw(&cape_right[global_frame_counter % 2],
592                                base.x- scroll_x, base.y);
593                 }
594               else
595                 {
596                   texture_draw(&cape_left[global_frame_counter % 2],
597                                base.x- scroll_x, base.y);
598                 }
599             }
600
601
602           if (!got_coffee)
603             {
604               if (physic.get_velocity_y() != 0)
605                 {
606                   if (dir == RIGHT)
607                     texture_draw(&smalltux_jump_right, base.x - scroll_x, base.y - 10);
608                   else
609                     texture_draw(&smalltux_jump_left, base.x - scroll_x, base.y - 10);                   
610                 }
611               else
612                 {
613                   if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
614                     {
615                       if (dir == RIGHT)
616                         texture_draw(&smalltux_stand_right, base.x - scroll_x, base.y - 9);
617                       else
618                         texture_draw(&smalltux_stand_left, base.x - scroll_x, base.y - 9);
619                     }
620                   else // moving
621                     {
622                       if (dir == RIGHT)
623                         texture_draw(&tux_right[(global_frame_counter/2) % tux_right.size()], 
624                                      base.x - scroll_x, base.y - 9);
625                       else
626                         texture_draw(&tux_left[(global_frame_counter/2) % tux_left.size()], 
627                                      base.x - scroll_x, base.y - 9);
628                     }
629                 }
630             }
631           else
632             {
633               /* Tux got coffee! */
634
635               if (dir == RIGHT)
636                 {
637                   texture_draw(&firetux_right[frame_], base.x- scroll_x, base.y);
638                 }
639               else
640                 {
641                   texture_draw(&firetux_left[frame_], base.x- scroll_x, base.y);
642                 }
643             }
644         }
645       else
646         {
647           if (timer_started(&invincible_timer))
648             {
649               /* Draw cape: */
650               if (dir == RIGHT)
651                 {
652                   texture_draw(&bigcape_right[global_frame_counter % 2],
653                                base.x- scroll_x - 8, base.y);
654                 }
655               else
656                 {
657                   texture_draw(&bigcape_left[global_frame_counter % 2],
658                                base.x-scroll_x - 8, base.y);
659                 }
660             }
661
662           if (!got_coffee)
663             {
664               if (!duck)
665                 {
666                   if (!timer_started(&skidding_timer))
667                     {
668                       if (!jumping || physic.get_velocity_y() > 0)
669                         {
670                           if (dir == RIGHT)
671                             {
672                               texture_draw(&bigtux_right[frame_],
673                                            base.x- scroll_x - 8, base.y);
674                             }
675                           else
676                             {
677                               texture_draw(&bigtux_left[frame_],
678                                            base.x- scroll_x - 8, base.y);
679                             }
680                         }
681                       else
682                         {
683                           if (dir == RIGHT)
684                             {
685                               texture_draw(&bigtux_right_jump,
686                                            base.x- scroll_x - 8, base.y);
687                             }
688                           else
689                             {
690                               texture_draw(&bigtux_left_jump,
691                                            base.x- scroll_x - 8, base.y);
692                             }
693                         }
694                     }
695                   else
696                     {
697                       if (dir == RIGHT)
698                         {
699                           texture_draw(&skidtux_right,
700                                        base.x- scroll_x - 8, base.y);
701                         }
702                       else
703                         {
704                           texture_draw(&skidtux_left,
705                                        base.x- scroll_x - 8, base.y);
706                         }
707                     }
708                 }
709               else
710                 {
711                   if (dir == RIGHT)
712                     {
713                       texture_draw(&ducktux_right, base.x- scroll_x - 8, base.y - 16);
714                     }
715                   else
716                     {
717                       texture_draw(&ducktux_left, base.x- scroll_x - 8, base.y - 16);
718                     }
719                 }
720             }
721           else
722             {
723               /* Tux has coffee! */
724
725               if (!duck)
726                 {
727                   if (!timer_started(&skidding_timer))
728                     {
729                       if (!jumping || physic.get_velocity_y() > 0)
730                         {
731                           if (dir == RIGHT)
732                             {
733                               texture_draw(&bigfiretux_right[frame_],
734                                            base.x- scroll_x - 8, base.y);
735                             }
736                           else
737                             {
738                               texture_draw(&bigfiretux_left[frame_],
739                                            base.x- scroll_x - 8, base.y);
740                             }
741                         }
742                       else
743                         {
744                           if (dir == RIGHT)
745                             {
746                               texture_draw(&bigfiretux_right_jump,
747                                            base.x- scroll_x - 8, base.y);
748                             }
749                           else
750                             {
751                               texture_draw(&bigfiretux_left_jump,
752                                            base.x- scroll_x - 8, base.y);
753                             }
754                         }
755                     }
756                   else
757                     {
758                       if (dir == RIGHT)
759                         {
760                           texture_draw(&skidfiretux_right,
761                                        base.x- scroll_x - 8, base.y);
762                         }
763                       else
764                         {
765                           texture_draw(&skidfiretux_left,
766                                        base.x- scroll_x - 8, base.y);
767                         }
768                     }
769                 }
770               else
771                 {
772                   if (dir == RIGHT)
773                     {
774                       texture_draw(&duckfiretux_right, base.x- scroll_x - 8, base.y - 16);
775                     }
776                   else
777                     {
778                       texture_draw(&duckfiretux_left, base.x- scroll_x - 8, base.y - 16);
779                     }
780                 }
781             }
782         }
783     }
784
785   if(dying)
786     text_drawf(&gold_text,"Penguins can fly !:",0,0,A_HMIDDLE,A_VMIDDLE,1);
787 }
788
789 void
790 Player::collision(void* p_c_object, int c_object)
791 {
792   BadGuy* pbad_c = NULL;
793
794   switch (c_object)
795     {
796     case CO_BADGUY:
797       pbad_c = (BadGuy*) p_c_object;
798       /* Hurt the player if he just touched it: */
799
800       if (!pbad_c->dying && !dying &&
801           !timer_started(&safe_timer) &&
802           pbad_c->mode != HELD)
803         {
804           if (pbad_c->mode == FLAT && input.fire == DOWN)
805             {
806               pbad_c->mode = HELD;
807               pbad_c->base.y-=8;
808             }
809           else if (pbad_c->mode == KICK)
810             {
811               if (base.y < pbad_c->base.y - 16)
812                 {
813                   /* Step on (stop being kicked) */
814
815                   pbad_c->mode = FLAT;
816                   play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
817                 }
818               else
819                 {
820                   /* Hurt if you get hit by kicked laptop: */
821                   if (!timer_started(&invincible_timer))
822                     {
823                       kill(SHRINK);
824                     }
825                   else
826                     {
827                       pbad_c->dying = DYING_FALLING;
828                       play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
829                       World::current()->add_score(pbad_c->base.x - scroll_x,
830                                                   pbad_c->base.y,
831                                                   25 * player_status.score_multiplier);
832                     }
833                 }
834             }
835           else
836             {
837               if (!timer_started(&invincible_timer ))
838                 {
839                   kill(SHRINK);
840                 }
841               else
842                 {
843                   pbad_c->kill_me();
844                 }
845             }
846           player_status.score_multiplier++;
847         }
848       break;
849     default:
850       break;
851     }
852
853 }
854
855 /* Kill Player! */
856
857 void
858 Player::kill(int mode)
859 {
860   play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
861
862   physic.set_velocity(0, physic.get_velocity_y());
863
864   if (mode == SHRINK && size == BIG)
865     {
866       if (got_coffee)
867         got_coffee = false;
868
869       size = SMALL;
870       base.height = 32;
871
872       timer_start(&safe_timer,TUX_SAFE_TIME);
873     }
874   else
875     {
876       if(size == BIG)
877         duck = true;
878
879       physic.enable_gravity(true);
880       physic.set_acceleration(0, 0);
881       physic.set_velocity(0, 7);
882       dying = DYING_SQUISHED;
883     }
884 }
885
886 void
887 Player::is_dying()
888 {
889   /* He died :^( */
890
891   --lives;
892   remove_powerups();
893   dying = DYING_NOT;
894 }
895
896 bool Player::is_dead()
897 {
898   if(base.y > screen->h)
899     return true;
900   else
901     return false;
902 }
903
904 /* Remove Tux's power ups */
905 void
906 Player::remove_powerups()
907 {
908   got_coffee = false;
909   size = SMALL;
910   base.height = 32;
911 }
912
913 void
914 Player::keep_in_bounds()
915 {
916   Level* plevel = World::current()->get_level();
917
918   /* Keep tux in bounds: */
919   if (base.x< 0)
920     base.x= 0;
921   else if(base.x< scroll_x)
922     base.x= scroll_x;
923   else if (base.x< 160 + scroll_x && scroll_x > 0 && debug_mode)
924     {
925       scroll_x = base.x- 160;
926       /*base.x+= 160;*/
927
928       if(scroll_x < 0)
929         scroll_x = 0;
930
931     }
932   else if (base.x > screen->w / 2 + scroll_x
933            && scroll_x < ((World::current()->get_level()->width * 32) - screen->w))
934     {
935       // FIXME: Scrolling needs to be handled by a seperate View
936       // class, doing it as a player huck is ugly
937
938       // Scroll the screen in past center:
939       scroll_x = base.x - screen->w / 2;
940
941       if (scroll_x > ((plevel->width * 32) - screen->w))
942         scroll_x = ((plevel->width * 32) - screen->w);
943     }
944   else if (base.x> 608 + scroll_x)
945     {
946       /* ... unless there's no more to scroll! */
947
948       /*base.x= 608 + scroll_x;*/
949     }
950
951   /* Keep in-bounds, vertically: */
952
953   if (base.y > screen->h)
954     {
955       kill(KILL);
956     }
957 }