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