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