- fixed duck-jump bug
[supertux.git] / src / player.cpp
1 //  $Id$
2 //
3 //  SuperTux -  A Jump'n Run
4 //  Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 #include <math.h>
21
22 #include "gameloop.h"
23 #include "globals.h"
24 #include "player.h"
25 #include "defines.h"
26 #include "scene.h"
27 #include "tile.h"
28 #include "sprite.h"
29 #include "screen.h"
30
31 Surface* tux_life;
32 std::vector<Surface*> tux_right;
33 std::vector<Surface*> tux_left;
34 Surface* smalltux_jump_left;
35 Surface* smalltux_jump_right;
36 Surface* smalltux_stand_left;
37 Surface* smalltux_stand_right;
38 Sprite*  smalltux_gameover;
39 Sprite*  smalltux_skid_left;
40 Sprite*  smalltux_skid_right;
41
42 Sprite*  smalltux_kick_left;
43 Sprite*  smalltux_kick_right;
44 Sprite*  smalltux_grab_left;
45 Sprite*  smalltux_grab_right;
46
47 Sprite*  largetux_kick_left;
48 Sprite*  largetux_kick_right;
49 Sprite*  largetux_grab_left;
50 Sprite*  largetux_grab_right;
51
52 Sprite*  largetux_stand_left;
53 Sprite*  largetux_stand_right;
54
55 Sprite* bigtux_right;
56 Sprite* bigtux_left;
57 Sprite* bigtux_right_jump;
58 Sprite* bigtux_left_jump;
59 Sprite* ducktux_right;
60 Sprite* ducktux_left;
61 Surface* skidtux_right;
62 Surface* skidtux_left;
63 Surface* firetux_right[3];
64 Surface* firetux_left[3];
65 Surface* bigfiretux_right[3];
66 Surface* bigfiretux_left[3];
67 Surface* bigfiretux_right_jump;
68 Surface* bigfiretux_left_jump;
69 Surface* duckfiretux_right;
70 Surface* duckfiretux_left;
71 Surface* skidfiretux_right;
72 Surface* skidfiretux_left;
73 Surface* cape_right[2];
74 Surface* cape_left[2];
75 Surface* bigcape_right[2];
76 Surface* bigcape_left[2];
77
78 PlayerKeymap keymap;
79
80 PlayerKeymap::PlayerKeymap()
81 {
82   keymap.jump  = SDLK_UP;
83   keymap.duck  = SDLK_DOWN;
84   keymap.left  = SDLK_LEFT;
85   keymap.right = SDLK_RIGHT;
86   keymap.fire  = SDLK_LCTRL;
87 }
88
89 void player_input_init(player_input_type* pplayer_input)
90 {
91   pplayer_input->down = UP;
92   pplayer_input->fire = UP;
93   pplayer_input->left = UP;
94   pplayer_input->old_fire = UP;
95   pplayer_input->right = UP;
96   pplayer_input->up = UP;
97 }
98
99 void
100 Player::init()
101 {
102   Level* plevel = World::current()->get_level();
103
104   holding_something = false;
105
106   base.width = 32;
107   base.height = 32;
108
109   size = SMALL;
110   got_coffee = false;
111
112   base.x = plevel->start_pos_x;
113   base.y = plevel->start_pos_y;
114   base.xm = 0;
115   base.ym = 0;
116   previous_base = old_base = base;
117   dir = RIGHT;
118   duck = false;
119
120   dying   = DYING_NOT;
121   jumping = false;
122
123   frame_main = 0;
124   frame_ = 0;
125   
126   player_input_init(&input);
127
128   invincible_timer.init(true);
129   skidding_timer.init(true);
130   safe_timer.init(true);
131   frame_timer.init(true);
132
133   physic.reset();
134 }
135
136 int
137 Player::key_event(SDLKey key, int state)
138 {
139   if(key == keymap.right)
140     {
141       input.right = state;
142       return true;
143     }
144   else if(key == keymap.left)
145     {
146       input.left = state;
147       return true;
148     }
149   else if(key == keymap.jump)
150     {
151       input.up = state;
152       return true;
153     }
154   else if(key == keymap.duck)
155     {
156       input.down = state;
157       return true;
158     }
159   else if(key == keymap.fire)
160     {
161       input.fire = state;
162       return true;
163     }
164   else
165     return false;
166 }
167
168 void
169 Player::level_begin()
170 {
171   base.x  = 100;
172   base.y  = 170;
173   base.xm = 0;
174   base.ym = 0;
175   previous_base = old_base = base;
176   duck = false;
177
178   dying = DYING_NOT;
179
180   player_input_init(&input);
181
182   invincible_timer.init(true);
183   skidding_timer.init(true);
184   safe_timer.init(true);
185   frame_timer.init(true);
186
187   physic.reset();
188 }
189
190 void
191 Player::action(double frame_ratio)
192 {
193   bool jumped_in_solid = false;
194
195   if (input.fire == UP)
196     holding_something = false;
197
198   /* Move tux: */
199   previous_base = base;
200
201   /* --- HANDLE TUX! --- */
202   if(dying == DYING_NOT)
203     handle_input();
204
205   physic.apply(frame_ratio, base.x, base.y);
206
207   if(dying == DYING_NOT) 
208     {
209       base_type target = base;
210
211       collision_swept_object_map(&old_base, &base);
212
213       // Don't accelerate Tux if he is running against a wall
214       if (target.x != base.x)
215         {
216           physic.set_velocity_x(0);
217         }
218
219       // special exception for cases where we're stuck under tiles after
220       // being ducked. In this case we drift out
221       if(!duck && on_ground() && old_base.x == base.x && old_base.y == base.y
222          && collision_object_map(base))
223         {
224           base.x += frame_ratio * WALK_SPEED * (dir ? 1 : -1);
225           previous_base = old_base = base;
226         }
227       keep_in_bounds();
228
229       // Land:
230       if (!on_ground())
231         {
232           physic.enable_gravity(true);
233           if(under_solid())
234             {
235               // fall down
236               physic.set_velocity_y(0);
237               jumped_in_solid = true;
238             }
239         }
240       else
241         {
242           /* Land: */
243           if (physic.get_velocity_y() < 0)
244             {
245               base.y = (int)(((int)base.y / 32) * 32);
246               physic.set_velocity_y(0);
247             }
248
249           physic.enable_gravity(false);
250           /* Reset score multiplier (for multi-hits): */
251           player_status.score_multiplier = 1;
252         }
253
254       if(jumped_in_solid)
255         {
256           if (isbrick(base.x, base.y) ||
257               isfullbox(base.x, base.y))
258             {
259               World::current()->trygrabdistro(base.x, base.y - 32,BOUNCE);
260               World::current()->trybumpbadguy(base.x, base.y - 64);
261
262               World::current()->trybreakbrick(base.x, base.y, size == SMALL);
263
264               bumpbrick(base.x, base.y);
265               World::current()->tryemptybox(base.x, base.y, RIGHT);
266             }
267
268           if (isbrick(base.x+ 31, base.y) ||
269               isfullbox(base.x+ 31, base.y))
270             {
271               World::current()->trygrabdistro(base.x+ 31, base.y - 32,BOUNCE);
272               World::current()->trybumpbadguy(base.x+ 31, base.y - 64);
273
274               if(size == BIG)
275                 World::current()->trybreakbrick(base.x+ 31, base.y, size == SMALL);
276
277               bumpbrick(base.x+ 31, base.y);
278               World::current()->tryemptybox(base.x+ 31, base.y, LEFT);
279             }
280         }
281
282       grabdistros();
283
284       if (jumped_in_solid)
285         {
286           ++base.y;
287           ++old_base.y;
288           if(on_ground())
289             {
290               /* Make sure jumping is off. */
291               jumping = false;
292             }
293         }
294     }
295
296   /* ---- DONE HANDLING TUX! --- */
297
298   // check some timers
299   skidding_timer.check();
300   invincible_timer.check();
301   safe_timer.check();
302 }
303
304 bool
305 Player::on_ground()
306 {
307   return ( issolid(base.x + base.width / 2, base.y + base.height) ||
308            issolid(base.x + 1, base.y + base.height) ||
309            issolid(base.x + base.width - 1, base.y + base.height)  );
310 }
311
312 bool
313 Player::under_solid()
314 {
315   return ( issolid(base.x + base.width / 2, base.y) ||
316            issolid(base.x + 1, base.y) ||
317            issolid(base.x + base.width - 1, base.y)  );
318 }
319
320 void
321 Player::handle_horizontal_input()
322 {
323   float vx = physic.get_velocity_x();
324   float vy = physic.get_velocity_y();
325   float ax = physic.get_acceleration_x();
326   float ay = physic.get_acceleration_y();
327
328   float dirsign = 0;
329   if(input.left == DOWN && input.right == UP && (!duck || physic.get_velocity_y() != 0)) {
330       dir = LEFT;
331       dirsign = -1;
332   } else if(input.left == UP && input.right == DOWN && (!duck || physic.get_velocity_y() != 0)) {
333       dir = RIGHT;
334       dirsign = 1;
335   }
336
337   if (input.fire == UP) {
338       ax = dirsign * WALK_ACCELERATION_X;
339       // limit speed
340       if(vx >= MAX_WALK_XM && dirsign > 0) {
341         vx = MAX_WALK_XM;
342         ax = 0;
343       } else if(vx <= -MAX_WALK_XM && dirsign < 0) {
344         vx = -MAX_WALK_XM;
345         ax = 0;
346       }
347   } else {
348       ax = dirsign * RUN_ACCELERATION_X;
349       // limit speed
350       if(vx >= MAX_RUN_XM && dirsign > 0) {
351         vx = MAX_RUN_XM;
352         ax = 0;
353       } else if(vx <= -MAX_RUN_XM && dirsign < 0) {
354         vx = -MAX_RUN_XM;
355         ax = 0;
356       }
357   }
358
359   // we can reach WALK_SPEED without any acceleration
360   if(dirsign != 0 && fabs(vx) < WALK_SPEED) {
361     vx = dirsign * WALK_SPEED;
362   }
363
364   // changing directions?
365   if(on_ground() && ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0))) {
366       if(fabs(vx)>SKID_XM && !skidding_timer.check()) {
367           skidding_timer.start(SKID_TIME);
368           play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER);
369           ax *= 2.5;
370       } else {
371           ax *= 2;
372       }
373   }
374
375   // we get slower when not pressing any keys
376   if(dirsign == 0) {
377       if(fabs(vx) < WALK_SPEED) {
378           vx = 0;
379           ax = 0;
380       } else if(vx < 0) {
381           ax = WALK_ACCELERATION_X * 1.5;
382       } else {
383           ax = WALK_ACCELERATION_X * -1.5;
384       }
385   }
386
387   // if we're on ice slow down acceleration or deceleration
388   if (isice(base.x, base.y + base.height))
389   {
390     /* the acceleration/deceleration rate on ice is inversely proportional to
391      * the current velocity.
392      */
393
394     // increasing 1 will increase acceleration/deceleration rate
395     // decreasing 1 will decrease acceleration/deceleration rate
396     //  must stay above zero, though
397     if (ax != 0) ax *= 1 / fabs(vx);
398   }
399
400   physic.set_velocity(vx, vy);
401   physic.set_acceleration(ax, ay);
402 }
403
404 void
405 Player::handle_vertical_input()
406 {
407   if(input.up == DOWN)
408     {
409       if (on_ground())
410         {
411           // jump higher if we are running
412           if (physic.get_velocity_x() > MAX_WALK_XM)
413             physic.set_velocity_y(5.8);
414           else
415             physic.set_velocity_y(5.2);
416
417           --base.y;
418           jumping = true;
419           if (size == SMALL)
420             play_sound(sounds[SND_JUMP], SOUND_CENTER_SPEAKER);
421           else
422             play_sound(sounds[SND_BIGJUMP], SOUND_CENTER_SPEAKER);
423         }
424     }
425   else if(input.up == UP && jumping)
426     {
427       jumping = false;
428       if(physic.get_velocity_y() > 0) {
429         physic.set_velocity_y(0);
430       }
431     }
432 }
433
434 void
435 Player::handle_input()
436 {
437   /* Handle horizontal movement: */
438     handle_horizontal_input();
439
440   /* Jump/jumping? */
441
442   if ( input.up == DOWN || (input.up == UP && jumping))
443     {
444       handle_vertical_input();
445     }
446
447   /* Shoot! */
448
449   if (input.fire == DOWN && input.old_fire == UP && got_coffee)
450     {
451       World::current()->add_bullet(base.x, base.y, physic.get_velocity_x(), dir);
452     }
453
454   /* tux animations: */
455   if(!frame_timer.check())
456     {
457       frame_timer.start(25);
458       if (input.right == UP && input.left == UP)
459         {
460           frame_main = 1;
461           frame_ = 1;
462         }
463       else
464         {
465           if ((input.fire == DOWN && (global_frame_counter % 2) == 0) ||
466               (global_frame_counter % 4) == 0)
467             frame_main = (frame_main + 1) % 4;
468
469           frame_ = frame_main;
470
471           if (frame_ == 3)
472             frame_ = 1;
473         }
474     }
475
476   /* Duck! */
477   if (input.down == DOWN && size == BIG && !duck && physic.get_velocity_y() == 0)
478     {
479       duck = true;
480       base.height = 32;                             
481       base.y += 32;
482       // changing base size confuses collision otherwise
483       old_base = previous_base = base;
484     }
485   else if(input.down == UP && size == BIG && duck && physic.get_velocity_y() == 0 && on_ground())
486     {
487       duck = false;
488       base.y -= 32;
489       base.height = 64;
490       old_base = previous_base = base;
491     }
492 }
493
494 void
495 Player::grabdistros()
496 {
497   /* Grab distros: */
498   if (!dying)
499     {
500       World::current()->trygrabdistro(base.x, base.y, NO_BOUNCE);
501       World::current()->trygrabdistro(base.x+ 31, base.y, NO_BOUNCE);
502
503       World::current()->trygrabdistro(base.x, base.y + base.height, NO_BOUNCE);
504       World::current()->trygrabdistro(base.x+ 31, base.y + base.height, NO_BOUNCE);
505
506       if(size == BIG)
507         {
508           World::current()->trygrabdistro(base.x, base.y + base.height / 2, NO_BOUNCE);
509           World::current()->trygrabdistro(base.x+ 31, base.y + base.height / 2, NO_BOUNCE);
510         }
511
512     }
513
514   /* Enough distros for a One-up? */
515   if (player_status.distros >= DISTROS_LIFEUP)
516     {
517       player_status.distros = player_status.distros - DISTROS_LIFEUP;
518       if(player_status.lives < MAX_LIVES)
519         ++player_status.lives;
520       /*We want to hear the sound even, if MAX_LIVES is reached*/
521       play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
522     }
523 }
524
525 void
526 Player::draw()
527 {
528   if (!safe_timer.started() || (global_frame_counter % 2) == 0)
529     {
530       if (dying == DYING_SQUISHED)
531         {
532           smalltux_gameover->draw(base.x - scroll_x, base.y);
533         }
534       else
535         {
536           if (size == SMALL)
537             {
538               if (invincible_timer.started())
539                 {
540                   if (dir == RIGHT)
541                     cape_right[global_frame_counter % 2]->draw(base.x- scroll_x, base.y);
542                   else
543                     cape_left[global_frame_counter % 2]->draw(base.x- scroll_x, base.y);
544                 }
545
546               if (!skidding_timer.started())
547                 {
548                   if (physic.get_velocity_y() != 0)
549                     {
550                       if (dir == RIGHT)
551                         smalltux_jump_right->draw( base.x - scroll_x, base.y - 10);
552                       else
553                         smalltux_jump_left->draw( base.x - scroll_x, base.y - 10);                   
554                     }
555                   else
556                     {
557                       if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
558                         {
559                           if (dir == RIGHT)
560                             smalltux_stand_right->draw( base.x - scroll_x, base.y - 9);
561                           else
562                             smalltux_stand_left->draw( base.x - scroll_x, base.y - 9);
563                         }
564                       else // moving
565                         {
566                           if (dir == RIGHT)
567                             tux_right[(global_frame_counter/2) % tux_right.size()]->draw(base.x - scroll_x, base.y - 9);
568                           else
569                             tux_left[(global_frame_counter/2) % tux_left.size()]->draw(base.x - scroll_x, base.y - 9);
570                         }
571                     }
572                 }
573               else
574                 {
575                   if (dir == RIGHT)
576                     smalltux_skid_right->draw(base.x - scroll_x, base.y);
577                   else
578                     smalltux_skid_left->draw(base.x - scroll_x, base.y); 
579                 }
580
581               if (holding_something && physic.get_velocity_y() == 0)
582                 {
583                   if (dir == RIGHT)
584                     smalltux_grab_right->draw(base.x - scroll_x, base.y);
585                   else
586                     smalltux_grab_left->draw(base.x - scroll_x, base.y);
587                 }
588             }
589           else // Large Tux
590             {
591               if (invincible_timer.started())
592                 {
593                   float capex = base.x + (base.width - bigcape_right[0]->w) / 2;
594                   capex -= scroll_x;
595                   float capey = base.y + (base.height - bigcape_right[0]->h) / 2;
596                 
597                   /* Draw cape (just not in ducked mode since that looks silly): */
598                   if (dir == RIGHT)
599                     bigcape_right[global_frame_counter % 2]->draw(capex, capey);
600                   else
601                     bigcape_left[global_frame_counter % 2]->draw(capex, capey);
602                 }
603
604               if (!got_coffee)
605                 {
606                   if (!duck)
607                     {
608                       if (!skidding_timer.started())
609                         {
610                           if (physic.get_velocity_y() == 0)
611                             {
612                               if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
613                                 {
614                                   if (dir == RIGHT)
615                                     largetux_stand_right->draw(base.x - scroll_x, base.y);
616                                   else
617                                     largetux_stand_left->draw(base.x - scroll_x, base.y);
618                                 }
619                               else // walking
620                                 {
621                                   if (dir == RIGHT)
622                                     bigtux_right->draw(base.x - scroll_x, base.y);
623                                   else
624                                     bigtux_left->draw(base.x - scroll_x, base.y);
625                                 }
626                             }
627                           else
628                             {
629                               if (dir == RIGHT)
630                                 bigtux_right_jump->draw(base.x - scroll_x, base.y);
631                               else
632                                 bigtux_left_jump->draw(base.x - scroll_x, base.y);
633                             }
634                         }
635                       else
636                         {
637                           if (dir == RIGHT)
638                             skidtux_right->draw(base.x - scroll_x - 8, base.y);
639                           else
640                             skidtux_left->draw(base.x - scroll_x - 8, base.y);
641                         }
642                     }
643                   else
644                     {
645                       if (dir == RIGHT)
646                         ducktux_right->draw(base.x - scroll_x, base.y);
647                       else
648                         ducktux_left->draw(base.x - scroll_x, base.y);
649                     }
650                 }
651               else
652                 {
653                   /* Tux has coffee! */
654                   if (!duck)
655                     {
656                       if (!skidding_timer.started())
657                         {
658                           if (!jumping || physic.get_velocity_y() > 0)
659                             {
660                               if (dir == RIGHT)
661                                 bigfiretux_right[frame_]->draw(base.x- scroll_x - 8, base.y);
662                               else
663                                 bigfiretux_left[frame_]->draw(base.x- scroll_x - 8, base.y);
664                             }
665                           else
666                             {
667                               if (dir == RIGHT)
668                                 bigfiretux_right_jump->draw(base.x- scroll_x - 8, base.y);
669                               else
670                                 bigfiretux_left_jump->draw(base.x- scroll_x - 8, base.y);
671                             }
672                         }
673                       else
674                         {
675                           if (dir == RIGHT)
676                             skidfiretux_right->draw(base.x- scroll_x - 8, base.y);
677                           else
678                             skidfiretux_left->draw(base.x- scroll_x - 8, base.y);
679                         }
680                     }
681                   else
682                     {
683                       if (dir == RIGHT)
684                         duckfiretux_right->draw( base.x- scroll_x - 8, base.y - 16);
685                       else
686                         duckfiretux_left->draw( base.x- scroll_x - 8, base.y - 16);
687                     }
688                 }
689
690               if (holding_something && !duck && physic.get_velocity_y() == 0)
691                 {
692                   if (dir == RIGHT)
693                     largetux_grab_right->draw(base.x - scroll_x, base.y);
694                   else
695                     largetux_grab_left->draw(base.x - scroll_x, base.y);
696                 }
697             }
698         }     
699     }
700
701   if (debug_mode)
702     fillrect(base.x - scroll_x, base.y, 32, 32, 75,75,75, 150);
703 }
704
705 void
706 Player::collision(void* p_c_object, int c_object)
707 {
708   BadGuy* pbad_c = NULL;
709
710   switch (c_object)
711     {
712     case CO_BADGUY:
713       pbad_c = (BadGuy*) p_c_object;
714
715      /* Hurt player if he touches a badguy */
716       if (!pbad_c->dying && !dying &&
717           !safe_timer.started() &&
718           pbad_c->mode != BadGuy::HELD)
719         {
720           if (pbad_c->mode == BadGuy::FLAT && input.fire == DOWN)
721             {
722               holding_something = true;
723               pbad_c->mode = BadGuy::HELD;
724               pbad_c->base.y-=8;
725             }
726           else if (pbad_c->mode == BadGuy::FLAT)
727             {
728               // Don't get hurt if we're kicking a flat badguy!
729             }
730           else if (pbad_c->mode == BadGuy::KICK)
731             {
732               /* Hurt if you get hit by kicked laptop: */
733               if (!invincible_timer.started())
734                 {
735                   kill(SHRINK);
736                 }
737               else
738                 {
739                    pbad_c->dying = DYING_FALLING;
740                    play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
741                    World::current()->add_score(pbad_c->base.x - scroll_x,
742                                                pbad_c->base.y,
743                                                25 * player_status.score_multiplier);
744                 }
745             }
746           else
747             {
748               if (!invincible_timer.started())
749                 {
750                   kill(SHRINK);
751                 }
752               else
753                 {
754                   pbad_c->kill_me();
755                 }
756             }
757           player_status.score_multiplier++;
758         }
759       break;
760     default:
761       break;
762     }
763
764 }
765
766 /* Kill Player! */
767
768 void
769 Player::kill(HurtMode mode)
770 {
771   play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
772
773   physic.set_velocity_x(0);
774
775   if (mode == SHRINK && size == BIG)
776     {
777       if (got_coffee)
778         {
779           got_coffee = false;
780         }
781       else
782         {
783           size = SMALL;
784           base.height = 32;
785           duck = false;
786         }
787       safe_timer.start(TUX_SAFE_TIME);
788     }
789   else
790     {
791       physic.enable_gravity(true);
792       physic.set_acceleration(0, 0);
793       physic.set_velocity(0, 7);
794       dying = DYING_SQUISHED;
795     }
796 }
797
798 void
799 Player::is_dying()
800 {
801   remove_powerups();
802   dying = DYING_NOT;
803 }
804
805 bool Player::is_dead()
806 {
807   if(base.y > screen->h)
808     return true;
809   else
810     return false;
811 }
812
813 /* Remove Tux's power ups */
814 void
815 Player::remove_powerups()
816 {
817   got_coffee = false;
818   size = SMALL;
819   base.height = 32;
820 }
821
822 void
823 Player::keep_in_bounds()
824 {
825   Level* plevel = World::current()->get_level();
826
827   /* Keep tux in bounds: */
828   if (base.x < 0)
829     { // Lock Tux to the size of the level, so that he doesn't fall of
830       // on the left side
831       base.x = 0;
832     }
833   else if (base.x < scroll_x)
834     { 
835       base.x = scroll_x;
836     }
837
838   /* Keep in-bounds, vertically: */
839   if (base.y > screen->h)
840     {
841       kill(KILL);
842     }
843
844   int scroll_threshold = screen->w/2 - 80;
845   if (debug_mode)
846     {
847       scroll_x += screen->w/2;
848       // Backscrolling for debug mode
849       if (scroll_x < base.x - 80)
850         scroll_x = base.x - 80;
851       else if (scroll_x > base.x + 80)
852         scroll_x = base.x + 80;
853       scroll_x -= screen->w/2;
854
855       if(scroll_x < 0)
856         scroll_x = 0;
857     }
858   else
859     {
860       if (base.x > scroll_threshold + scroll_x
861           && scroll_x < ((World::current()->get_level()->width * 32) - screen->w))
862         {
863           // FIXME: Scrolling needs to be handled by a seperate View
864           // class, doing it as a player huck is ugly
865           
866           // Scroll the screen in past center:
867           scroll_x = base.x - scroll_threshold;
868           
869           // Lock the scrolling to the levelsize, so that we don't
870           // scroll over the right border
871           if (scroll_x > 32 * plevel->width - screen->w)
872             scroll_x = 32 * plevel->width - screen->w;
873         }
874     }
875 }
876
877 // EOF //
878