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