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