source: abuse/trunk/src/cop.cpp @ 634

Last change on this file since 634 was 577, checked in by Sam Hocevar, 11 years ago

game: get rid of milli_wait() and rewrite the fixed framerate handling.

File size: 27.4 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5 *
6 *  This software was released into the Public Domain. As with most public
7 *  domain software, no warranty is made or implied by Crack dot Com, by
8 *  Jonathan Clark, or by Sam Hocevar.
9 */
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include "common.h"
16
17#include "lisp.h"
18#include "lisp_gc.h"
19#include "compiled.h"
20#include "objects.h"
21#include "level.h"
22#include "game.h"
23#include "jrand.h"
24#include "clisp.h"
25#include "ant.h"
26#include "dev.h"
27
28enum { point_angle, fire_delay1 };
29
30#define SHOTGUN  10
31#define GRENADE  2
32#define ROCKET   3
33#define PLASMA   4
34#define FIREBOMB 5
35#define DFRIS    6
36#define LSABER   7
37
38signed char small_fire_off[24*2]=  // x & y offset from character to end of gun.
39  { 17,20,     // 1
40    17,23,     // 2
41    17,28,
42    15,33,
43    11,39,     // 5
44    7,43,
45    -3,44,     // 7
46    -10,42,
47    -16,39,
48    -20,34,
49    -20,28,
50    -20,25,
51    -19,20,
52    -19,16,
53    -16,14,
54    -14,11,
55    -11,9,
56    -7,8,
57    -3,8,
58    2,8,
59    6,9,
60    10,10,
61    14,13,
62    16,15 };
63
64signed char large_fire_off[24*2]=
65  { 18,25,
66    17,30,
67    15,34,
68    14,36,
69    10,39,
70    7,41,
71    4,42,
72    -3,41,
73    -8,39,
74    -11,37,
75    -14,33,
76    -16,30,
77    -18,25,
78    -17,21,
79    -14,17,
80    -11,15,
81    -7,13,
82    -4,12,
83    3,12,
84    9,12,
85    12,15,
86    14,16,
87    15,18,
88    16,21 };
89
90
91enum { in_climbing_area,
92    disable_top_draw,
93    just_hit,
94    ship_pan_x,
95    special_power,
96    used_special_power,
97    last1_x, last1_y,
98    last2_x, last2_y,
99    has_saved_this_level,
100    r_ramp, g_ramp, b_ramp,
101        is_teleporting,
102       just_fired};
103
104
105enum { sgb_speed,
106       sgb_angle,
107       sgb_lastx,
108       sgb_lasty,
109       sgb_bright_color,
110       sgb_medium_color,
111       sgb_lifetime };
112
113enum { NO_POWER,
114       FAST_POWER,
115       FLY_POWER,
116       SNEAKY_POWER,
117       HEALTH_POWER } ;
118
119enum { top_point_angle,
120       top_fire_delay1,
121       top_just_fired };
122
123inline int angle_diff(int a1, int a2)
124{
125  if (a1<a2)
126  { if ((a2-a1)<180)
127      return a2-a1;
128    else return 360-a2+a1;
129  } else
130  {
131    if ((a1-a2)<180)
132      return a1-a2;
133    else return 360-a1+a2;
134  }
135  return 0;
136}
137
138void *top_ai()
139{
140  game_object *o=current_object;
141  if (o->total_objects())            // make sure we are linked to the main character
142  {
143    game_object *q=o->get_object(0);
144
145    view *v=q->controller();
146    if (v)
147    {
148      if (!v->freeze_time)
149      {
150    o->direction=1;                 // always face right
151
152    if (q->direction<0)
153          q->x+=4;
154    int i;
155    signed char *fire_off=o->otype==S_DFRIS_TOP ? large_fire_off :
156                                    (o->otype==S_ROCKET_TOP ? large_fire_off :
157                     (o->otype==S_BFG_TOP ? large_fire_off : small_fire_off));
158    signed char *f=fire_off,*fb=NULL;
159    int best_diff=200,best_num=0;
160    int iy=f[1],ix=f[6*2];
161
162    int best_angle=lisp_atan2(q->y-iy-v->pointer_y,v->pointer_x-q->x-ix);
163    for (i=0; i<24; i++,f+=2)             // check all the angles to see which would best fit animation wise
164    {
165      int this_angle=lisp_atan2(f[1]-iy,f[0]-ix);
166      int this_diff=angle_diff(this_angle,best_angle);
167      if (this_diff<best_diff)
168      {
169        best_diff=this_diff;
170        best_num=i;
171        fb=f;
172      }
173    }
174
175
176    // if the pointer is too close to the player go with the angle shown, not the angle through the pointer
177    if (abs(q->y-fb[1]-v->pointer_y)<45 && abs(v->pointer_x-q->x+fb[0])<40)
178      o->lvars[point_angle]=lisp_atan2(fb[1]-iy,fb[0]-ix);
179    else
180      o->lvars[point_angle]=lisp_atan2(q->y-fb[1]-v->pointer_y,v->pointer_x-(q->x+fb[0]));
181
182
183    if (q->direction<0)
184          q->x-=4;
185
186    o->x=q->x;
187    o->y=q->y+29-q->picture()->Size().y;
188
189    rand_on+=o->lvars[point_angle];
190    o->current_frame=best_num;
191
192
193    if (o->lvars[fire_delay1])
194      o->lvars[fire_delay1]--;
195
196    o->otype=weapon_types[v->current_weapon];  // switch to correct top part
197      }
198    }
199  }
200  return true_symbol;
201}
202
203
204static int player_fire_weapon(game_object *o, int type, game_object *target, int angle, signed char *fire_off)
205{
206
207  if (!o->total_objects()) return 0;
208  game_object *other=o->get_object(0);
209  int ox=other->x,oy=other->y;
210  if (other->direction<0) other->x+=4;
211
212  int firex=other->x+fire_off[o->current_frame*2];
213  int firey=other->y-fire_off[o->current_frame*2+1];
214
215
216
217  // fire try to move up to gun level
218
219  int32_t x2=o->x,y2=firey;
220//  current_level->foreground_intersect(other->x,other->y,x2,y2);      // find first location we can actuall "see"
221//  current_level->all_boundary_setback(o,other->x,other->y,x2,y2);       // to make we don't fire through walls
222  other->y=y2;
223
224  if (other->y==firey)             // now try to move out to end of gun if we were not blocked above
225  {
226    x2=firex;
227    current_level->foreground_intersect(other->x,other->y,x2,y2);      // find first location we can actuall "see"
228    current_level->all_boundary_setback(other,other->x,other->y,x2,y2);       // to make we don't fire through walls
229    o->x=x2;
230  }
231
232  void *list=NULL;
233  PtrRef r1(list);
234  push_onto_list(LPointer::Create(target),list);
235  push_onto_list(LNumber::Create(angle),list);
236  push_onto_list(LNumber::Create(y2),list);
237  push_onto_list(LNumber::Create(x2),list);
238  push_onto_list(LNumber::Create(type),list);
239  push_onto_list(LPointer::Create(o->get_object(0)),list);
240  ((LSymbol *)l_fire_object)->EvalFunction(list);
241  o->lvars[top_just_fired]=1;
242  other->lvars[just_fired]=1;
243  other->x=ox;
244  other->y=oy;
245
246  return 1;
247}
248
249
250
251void *laser_ufun(void *args)
252{
253  game_object *o=current_object;
254  PtrRef r1(args);
255  void *signal=CAR(args);  args=CDR(args);
256  void *ret=NULL;
257
258  if (signal==l_FIRE)
259  {
260    if (!o->lvars[fire_delay1])                   // make sur we are not waiting of previous fire
261    {
262      int32_t value=lnumber_value(CAR(args)->Eval());
263      if (value)                                   // do we have ammo ?
264      {
265    o->lvars[fire_delay1]=3;
266    if (player_fire_weapon(o,SHOTGUN,NULL,o->lvars[point_angle],small_fire_off))
267          ret=LNumber::Create(-1);
268    else ret=LNumber::Create(0);
269      } else
270      {
271    o->lvars[fire_delay1]=5;                  // no ammo, set large fire delay for next shot
272    player_fire_weapon(o,SHOTGUN,NULL,o->lvars[point_angle],small_fire_off);
273    ret=LNumber::Create(0);
274      }
275    } else ret=LNumber::Create(0);                // can't fire yet, return 0 ammo subtract
276  }
277  return ret;
278}
279
280
281static int ammo_type(int otype)
282{
283  if (otype==S_GRENADE_TOP)
284    return GRENADE;
285  else if (otype==S_FIREBOMB_TOP)
286    return FIREBOMB;
287  else if (otype==S_DFRIS_TOP)
288    return DFRIS;
289  else return SHOTGUN;
290}
291
292
293void *top_ufun(void *args)                       // generic top character ai GRENADE && FIREBOMB
294{
295  game_object *o=current_object;
296  PtrRef r1(args);
297  void *signal=CAR(args);  args=CDR(args);
298  void *ret=NULL;
299
300  if (signal==l_FIRE)
301  {
302    if (!o->lvars[fire_delay1])                   // make sur we are not waiting of previous fire
303    {
304      int32_t value=lnumber_value(CAR(args)->Eval());
305      if (value)                                   // do we have ammo ?
306      {
307    o->lvars[fire_delay1]=6;
308    if (player_fire_weapon(o,ammo_type(o->otype),NULL,o->lvars[point_angle],
309                   o->otype==DFRIS ? large_fire_off : small_fire_off ))
310          ret=LNumber::Create(-1);
311    else ret=LNumber::Create(0);
312      } else ret=LNumber::Create(0);
313    } else ret=LNumber::Create(0);                // can't fire yet, return 0 ammo subtract
314  }
315  return ret;
316}
317
318static int climb_handler(game_object *, int xm, int ym, int but);
319
320void *plaser_ufun(void *args)
321{
322  game_object *o=current_object;
323  PtrRef r1(args);
324  void *signal=CAR(args);  args=CDR(args);
325  void *ret=NULL;
326
327  if (signal==l_FIRE)
328  {
329    if (!o->lvars[fire_delay1])                   // make sur we are not waiting of previous fire
330    {
331      int32_t value=lnumber_value(CAR(args)->Eval());
332      if (value)                                   // do we have ammo ?
333      {
334    o->lvars[fire_delay1]=2;
335    if (player_fire_weapon(o,PLASMA,NULL,o->lvars[point_angle],small_fire_off))
336          ret=LNumber::Create(-1);
337    else ret=LNumber::Create(0);
338      } else ret=LNumber::Create(0);
339    } else ret=LNumber::Create(0);                // can't fire yet, return 0 ammo subtract
340  }
341  return ret;
342}
343
344void *lsaber_ufun(void *args)
345{
346  game_object *o=current_object;
347  PtrRef r1(args);
348  void *signal=CAR(args);  args=CDR(args);
349  void *ret=NULL;
350
351  if (signal==l_FIRE)
352  {
353    if (!o->lvars[fire_delay1])                   // make sur we are not waiting of previous fire
354    {
355      int32_t value=lnumber_value(CAR(args)->Eval());
356      if (value)                                   // do we have ammo ?
357      {
358    o->lvars[fire_delay1]=1;
359    if (player_fire_weapon(o,LSABER,NULL,o->lvars[point_angle]+(current_level->tick_counter()&7)-8,
360                   small_fire_off))
361          ret=LNumber::Create(-1);
362    else ret=LNumber::Create(0);
363      } else ret=LNumber::Create(0);
364    } else ret=LNumber::Create(0);                // can't fire yet, return 0 ammo subtract
365  }
366  return ret;
367}
368
369
370
371void *player_rocket_ufun(void *args)
372{
373  game_object *o=current_object;
374  PtrRef r1(args);
375  void *signal=CAR(args);  args=CDR(args);
376  void *ret=NULL;
377  int xd,yd,cl=0xfffffff,d;
378  if (signal==l_FIRE)
379  {
380    if (!o->lvars[fire_delay1])                   // make sur we are not waiting of previous fire
381    {
382      int32_t value=lnumber_value(CAR(args)->Eval());
383      if (value)                                   // do we have ammo ?
384      {
385    o->lvars[fire_delay1]=6;
386    game_object *target=NULL,*p,*bot=o->total_objects() ? o->get_object(0) : 0;
387    if (bad_guy_array)
388    {
389      game_object *other=current_object->total_objects() ? current_object->get_object(0) : 0;
390      for (p=current_level->first_active_object(); p; p=p->next_active)
391      {
392        xd=abs(p->x-o->x);
393        yd=abs(p->y-o->y);
394        if (xd<160 && yd<130 && bad_guy_array[p->otype] && p!=other)
395        {
396          if (p->targetable() &&
397          !(p->otype==S_ROCKET && p->total_objects() && p->get_object(0)==bot))  // don't track onto own missles
398          {
399        d=xd*xd+yd*yd;
400        if (d<cl)
401        {
402          cl=d;
403          target=p;
404        }
405          }
406        }
407      }
408    }
409    if (player_fire_weapon(o,ROCKET,target,o->lvars[point_angle],large_fire_off))
410          ret=LNumber::Create(-1);
411    else ret=LNumber::Create(0);
412
413      } else ret=LNumber::Create(0);
414    } else ret=LNumber::Create(0);                // can't fire yet, return 0 ammo subtract
415  }
416  return ret;
417}
418
419static int player_move(game_object *o, int xm, int ym, int but)
420{
421  if (!o->lvars[in_climbing_area])
422  {
423    if (o->state==S_climbing)
424    {
425      o->set_gravity(1);
426      o->set_state(run_jump_fall);
427    }
428    o->next_picture();
429    return o->mover(xm,ym,but);
430  } else return climb_handler(o,xm,ym,but);
431
432}
433
434
435static void undo_special_power(game_object *o)
436{
437  switch (o->lvars[special_power])
438  {
439    case SNEAKY_POWER :
440    {
441      if (o->lvars[used_special_power]>0)
442        o->lvars[used_special_power]--;
443    } break;
444    case FAST_POWER :
445    {
446      o->lvars[used_special_power]=0;
447    } break;
448  }
449}
450
451static void do_special_power(game_object *o, int xm, int ym, int but, game_object *top)
452{
453  switch (o->lvars[special_power])
454  {
455    case FLY_POWER :
456    {
457      game_object *cloud=create(S_CLOUD,o->x+o->direction*-10,o->y+jrand()%5);
458      if (current_level)
459        current_level->add_object(cloud);
460      o->set_state(run_jump);
461      o->set_gravity(1);
462      o->set_yacel(0);
463      if (o->yvel()>0) o->set_yvel(o->yvel()/2);
464      if (ym<0)
465        o->set_yvel(o->yvel()-3);
466      else
467        o->set_yvel(o->yvel()-2);
468      the_game->play_sound(S_FLY_SND,32,o->x,o->y);
469    } break;
470    case FAST_POWER :
471    {
472      if ((current_level->tick_counter()%16)==0)
473      the_game->play_sound(S_SPEED_SND,100,o->x,o->y);
474
475      o->lvars[used_special_power]=1;
476      o->lvars[last1_x]=o->x;
477      o->lvars[last1_y]=o->y;
478      int32_t oyvel=o->yvel();
479      int in=o->lvars[in_climbing_area];
480
481      player_move(o,xm,ym,but);
482      if (ym<0 && !oyvel && o->yvel()<0)             // if they just jumped, make them go higher
483      o->set_yvel(o->yvel()+o->yvel()/3);
484      o->lvars[in_climbing_area]=in;
485
486      o->lvars[last2_x]=o->x;
487      o->lvars[last2_x]=o->y;
488    } break;
489    case SNEAKY_POWER :
490    {
491      if (o->lvars[used_special_power]<15)
492        o->lvars[used_special_power]++;
493    } break;
494  }
495}
496
497static int climb_off_handler(game_object *o)
498{
499  if (o->next_picture())
500    o->controller()->pan_y-=4;
501  else
502  {
503    o->y-=28;
504    o->controller()->pan_y+=28;
505    o->controller()->last_y-=28;
506    o->set_state(stopped);
507  }
508  return 0;
509}
510
511
512static int climb_on_handler(game_object *o)
513{
514  if (o->next_picture())
515    o->controller()->pan_y+=4;
516  else
517    o->set_state((character_state)S_climbing);
518  return 0;
519}
520
521static int climb_handler(game_object *o, int xm, int ym, int but)
522{
523  int yd=o->lvars[in_climbing_area];  // see how from the top we are
524  o->lvars[in_climbing_area]=0;          // set 0, ladders will set back to proper if still in area
525  if (o->state==S_climb_off)
526    climb_off_handler(o);
527  else if (o->state==S_climb_on)
528    climb_on_handler(o);
529  else
530  {
531    if (o->state==S_climbing)
532    {
533      if (ym>0)                       // going down
534      {
535
536    if (o->current_frame==0) o->current_frame=9;
537      o->current_frame--;
538
539/*    if (o->lvars[special_power]==FAST_POWER)
540    {
541      int32_t xv=0,yv=4;
542      o->try_move(o->x,o->y,xv,yv,1);
543      if (yv==4)
544        o->y+=3;
545      else
546      {
547        o->set_gravity(1);
548          o->set_state(run_jump_fall);
549      }
550    }
551    else */ o->y+=3;
552
553
554      } else if (ym<0)
555      {
556    if (yd<32)
557      o->set_state((character_state)S_climb_off);
558    else
559    {
560      if (!o->next_picture()) o->set_state((character_state)S_climbing);
561      o->y-=3;
562    }
563      }
564      if (xm)                     // trying to get off the ladder, check to see if that's ok
565      {
566    int32_t x2=0,y2=-20;
567    o->try_move(o->x,o->y,x2,y2,3);
568    if (y2==-20)
569    {
570      o->set_gravity(1);
571      if (ym>=0)
572        o->set_state(run_jump_fall);
573      else
574      { o->set_state(run_jump);
575        o->set_yvel(get_ability(o->otype,jump_yvel));
576      }
577    }
578      }
579    }  else if (ym>0 && yd<10)
580    {
581      o->y+=28;
582      o->controller()->pan_y-=28;
583      o->controller()->last_y+=28;
584      o->set_state((character_state)S_climb_on);
585    }
586    else if (o->yvel()>=0 && (ym>0 || (ym<0 && yd>8)))
587    {
588      o->set_state((character_state)S_climbing);
589      o->set_gravity(0);
590      o->set_xvel(0);
591      o->set_yvel(0);
592      o->set_xacel(0);
593      o->set_yacel(0);
594      return 0;
595    } else
596    {
597      o->next_picture();
598      return o->mover(xm,ym,but);
599    }
600  }
601  return 0;
602}
603
604
605void *cop_mover(int xm, int ym, int but)
606{
607
608  int ret=0;
609  game_object *o=current_object,*top;
610  if (o->controller() && o->controller()->freeze_time)
611  {
612    o->controller()->freeze_time--;
613    if (but || o->controller()->key_down(JK_SPACE) || o->controller()->key_down(JK_ENTER))
614      o->controller()->freeze_time=0;
615  }
616  else
617  {
618    if (!o->total_objects())                  // if no top create one
619    {
620      top=create(S_MGUN_TOP,o->x,o->y,0,0);
621      current_level->add_object_after(top,o);
622      o->add_object(top);
623      top->add_object(o);
624    } else top=o->get_object(0);
625
626    if (o->yvel()>10)
627    {
628      o->set_yacel(0);
629      o->set_yvel(o->yvel()-1);            // terminal velocity
630    }
631
632    if (o->aistate()==0)  // just started, wait for button
633    {
634      o->set_aistate(1);
635    } else if (o->aistate()==1)         // normal play
636    {
637      if (o->hp()==0)
638      {
639    o->set_aistate(2);                // go to deing state
640    o->set_state(dead);
641      }
642      else
643      {
644    if (o->hp()<40 && (current_level->tick_counter()%16)==0) // if low on health play heart beat
645      the_game->play_sound(S_LOW_HEALTH_SND,127,o->x,o->y);
646    else if (o->hp()<15 && (current_level->tick_counter()%8)==0) // if low on health play heart beat
647      the_game->play_sound(S_LOW_HEALTH_SND,127,o->x,o->y);
648    else if (o->hp()<7 && (current_level->tick_counter()%4)==0) // if low on health play heart beat
649      the_game->play_sound(S_LOW_HEALTH_SND,127,o->x,o->y);
650
651    if (but&1)
652        do_special_power(o,xm,ym,but,top);
653    else
654    undo_special_power(o);
655    ret=player_move(o,xm,ym,but);
656    top->x=o->x;
657    top->y=o->y+29-top->picture()->Size().y;
658
659    if ((but&2) && !o->lvars[is_teleporting] && o->state!=S_climbing && o->state!=S_climb_off)
660    {
661      void *args=NULL;
662      PtrRef r1(args);
663      view *v=o->controller();
664
665      push_onto_list(LNumber::Create(v->weapon_total(v->current_weapon)),args);
666      push_onto_list(l_FIRE,args);
667
668      current_object=top;
669      void *ret = ((LSymbol *)figures[top->otype]->get_fun(OFUN_USER_FUN))->EvalFunction(args);
670      current_object=o;
671      v->add_ammo(v->current_weapon,lnumber_value(ret));
672    }
673      }
674    } else if (o->aistate()==3)
675    {
676      if (!o->controller() || o->controller()->key_down(JK_SPACE))
677      {
678        // call the user function to reset the player
679    ((LSymbol *)l_restart_player)->EvalFunction(NULL);
680    o->controller()->reset_player();
681    o->set_aistate(0);
682      } else if (o->controller() && o->controller()->local_player())
683        the_game->show_help(symbol_str("space_cont"));
684
685    } else o->set_aistate(o->aistate()+1);
686  }
687
688  return LNumber::Create(ret);
689}
690
691
692
693void *ladder_ai()
694{
695  view *f=player_list;
696  game_object *o=current_object;
697  if (o->total_objects())
698  {
699    game_object *other=o->get_object(0);
700    for (; f; f=f->next)
701    {
702      int mex=f->focus->x;
703      int mey=f->focus->y;
704
705      if (o->x<=mex && o->y<=mey && other->x>=mex && other->y>=mey)
706      {
707    if (f->focus->state==S_climbing)
708      f->focus->x=(o->x+other->x)/2;
709        f->focus->lvars[in_climbing_area]=mey-o->y;
710      }
711    }
712  }
713  return true_symbol;
714}
715
716
717
718void *player_draw(int just_fired_var, int num)
719{
720  game_object *o=current_object;
721  if (num==0)
722  {
723    if (o->lvars[just_fired_var])
724    {
725      o->draw_tint(S_bright_tint);
726      o->lvars[just_fired_var]=0;
727    } else
728      o->drawer();
729  }
730  else
731  {
732    if (o->lvars[just_fired_var])
733    {
734      o->draw_double_tint(lnumber_value(((LArray *)((LSymbol *)l_player_tints)->GetValue())->Get(num)), S_bright_tint);
735      o->lvars[just_fired_var]=0;
736    } else
737      o->draw_tint(lnumber_value(((LArray *)((LSymbol *)l_player_tints)->GetValue())->Get(num)));
738  }
739  return NULL;
740}
741
742
743void *top_draw()
744{
745  game_object *o=current_object;
746  if (o->total_objects())
747  {
748    game_object *bot=o->get_object(0);
749    if (bot->state==stopped  || bot->state==running ||
750    bot->state==run_jump || bot->state==run_jump_fall ||
751    bot->state==end_run_jump)
752    {
753      int oldy=o->y;
754      o->x=bot->x;
755      if (bot->direction<0)
756        o->x+=4;
757      o->y=bot->y+29-bot->picture()->Size().y;
758
759      void *ret=NULL;
760      PtrRef r1(ret);
761
762      push_onto_list(LNumber::Create(bot->get_tint()),ret);
763
764      if (bot->lvars[special_power]==SNEAKY_POWER)
765      {
766    if (bot->lvars[used_special_power]==0)
767      player_draw(top_just_fired,bot->get_tint());
768    else if (bot->lvars[used_special_power]<15)
769      o->draw_trans(bot->lvars[used_special_power],16);
770    else
771      o->draw_predator();
772      } else
773        ((LSymbol *)l_player_draw)->EvalFunction(ret);
774
775      o->y=oldy;
776      if (bot->direction<0)
777        o->x-=4;
778    }
779  }
780  return NULL;
781}
782
783
784
785void *bottom_draw()
786{
787  game_object *o=current_object;
788
789  if (o->lvars[r_ramp] || o->lvars[g_ramp] || o->lvars[b_ramp])
790  {
791    int r=o->lvars[r_ramp];
792    if (r>7) r-=7;
793    else r=0;
794    o->lvars[r_ramp]=r;
795
796    int g=o->lvars[g_ramp];
797    if (g>7) g-=7;
798    else g=0;
799    o->lvars[g_ramp]=g;
800
801    int b=o->lvars[b_ramp];
802    if (b>7) b-=7;
803    else b=0;
804    o->lvars[b_ramp]=b;
805
806    palette *p=pal->copy();
807    uint8_t *addr=(uint8_t *)p->addr();
808    int ra,ga,ba;
809
810    for (int i=0; i<256; i++)
811    {
812      ra=(int)*addr+r; if (ra>255) ra=255; else if (ra<0) r=0; *addr=(uint8_t)ra; addr++;
813      ga=(int)*addr+g; if (ga>255) ga=255; else if (ga<0) g=0; *addr=(uint8_t)ga; addr++;
814      ba=(int)*addr+b; if (ba>255) ba=255; else if (ba<0) b=0; *addr=(uint8_t)ba; addr++;
815    }
816    p->load();
817    delete p;
818  }
819
820  if (o->aistate()>0)
821  {
822    switch (o->lvars[special_power])
823    {
824      case NO_POWER :
825      { player_draw(just_fired,o->get_tint()); } break;
826
827      case HEALTH_POWER :
828      {
829    player_draw(just_fired,o->get_tint());
830    if (o->controller() && o->controller()->local_player())
831      cache.img(S_health_image)->put_image(screen,o->controller()->cx2-20,
832                        o->controller()->cy1+5,1);
833      } break;
834      case FAST_POWER :
835      {
836    ((LSymbol *)l_draw_fast)->EvalFunction(NULL);
837    int old_state=o->state;
838    switch (o->state)
839    {
840      case stopped : o->state=(character_state)S_fast_stopped; break;
841      case running : o->state=(character_state)S_fast_running; break;
842      case start_run_jump : o->state=(character_state)S_fast_start_run_jump; break;
843      case run_jump : o->state=(character_state)S_fast_run_jump; break;
844      case run_jump_fall : o->state=(character_state)S_fast_run_jump_fall; break;
845      case end_run_jump : o->state=(character_state)S_fast_end_run_jump; break;
846      default: break;
847    }
848
849    player_draw(just_fired,o->get_tint());
850    o->state=(character_state)old_state;
851    if (o->controller() && o->controller()->local_player())
852      cache.img(S_fast_image)->put_image(screen,o->controller()->cx2-20,
853                        o->controller()->cy1+5,1);
854      } break;
855      case FLY_POWER :
856      {
857    int old_state=o->state;
858    switch (o->state)
859    {
860      case stopped : o->state=(character_state)S_fly_stopped; break;
861      case running : o->state=(character_state)S_fly_running; break;
862      case start_run_jump : o->state=(character_state)S_fly_start_run_jump; break;
863      case run_jump : o->state=(character_state)S_fly_run_jump; break;
864      case run_jump_fall : o->state=(character_state)S_fly_run_jump_fall; break;
865      case end_run_jump : o->state=(character_state)S_fly_end_run_jump; break;
866      default: break;
867    }
868
869    player_draw(just_fired,o->get_tint());
870    o->state=(character_state)old_state;
871
872    if (o->controller() && o->controller()->local_player())
873      cache.img(S_fly_image)->put_image(screen,o->controller()->cx2-20,
874                        o->controller()->cy1+5,1);
875      } break;
876      case SNEAKY_POWER :
877      {
878    if (o->lvars[used_special_power]==0)
879      player_draw(just_fired,o->get_tint());
880    else if (o->lvars[used_special_power]<15)
881      o->draw_trans(o->lvars[used_special_power],16);
882    else
883      o->draw_predator();
884
885    if (o->controller() && o->controller()->local_player())
886      cache.img(S_sneaky_image)->put_image(screen,o->controller()->cx2-20,
887                        o->controller()->cy1+5,1);
888      } break;
889    }
890  }
891  return NULL;
892}
893
894
895
896void *sgun_ai()
897{
898  game_object *o=current_object;
899
900  if (o->lvars[sgb_lifetime]==0)
901    return NULL;
902  o->lvars[sgb_lifetime]--;
903
904  o->lvars[sgb_lastx]=o->x;
905  o->lvars[sgb_lasty]=o->y;
906  o->lvars[sgb_speed]=o->lvars[sgb_speed]*6/5;
907
908  int32_t ang=o->lvars[sgb_angle];
909  int32_t mag=o->lvars[sgb_speed];
910
911  int32_t xvel=(lisp_cos(ang))*(mag);
912  current_object->set_xvel(xvel>>16);
913  current_object->set_fxvel((xvel&0xffff)>>8);
914  int32_t yvel=-(lisp_sin(ang))*(mag);
915  current_object->set_yvel(yvel>>16);
916  current_object->set_fyvel((yvel&0xffff)>>8);
917
918
919  int whit=0;
920  game_object *who=o->bmove(whit, o->total_objects() ? o->get_object(0) : 0);
921
922  if (whit || (who && figures[who->otype]->get_cflag(CFLAG_UNACTIVE_SHIELD) && who->total_objects() &&
923           who->get_object(0)->aistate()==0))
924  {
925    o->lvars[sgb_lifetime]=0;
926    game_object *n=create(S_EXPLODE5,o->x+jrand()%4,o->y+jrand()%4);
927    current_level->add_object(n);
928  } else if (who && figures[who->otype]->get_cflag(CFLAG_HURTABLE))
929  {
930    o->lvars[sgb_lifetime]=0;
931    game_object *n=create(S_EXPLODE3,o->x+jrand()%4,o->y+jrand()%4);
932    current_level->add_object(n);
933     who->do_damage(5,o,o->x,o->y,(lisp_cos(ang)*10)>>16,(lisp_sin(ang)*10)>>16);
934  }
935  return true_symbol;
936}
937
938
939
940void *mover_ai()
941{
942  game_object *o=current_object;
943  if (o->total_objects()==2)
944  {
945    if (o->aistate()<2)
946    {
947      game_object *obj=o->get_object(1);
948      o->remove_object(obj);
949      game_object *d=o->get_object(0);
950      d->add_object(obj);
951      d->set_aistate(d->aitype());
952    } else
953    {
954      o->set_aistate(o->aistate()-1);
955      game_object *d=o->get_object(0);
956      game_object *obj=o->get_object(1);
957
958      obj->x=d->x-(d->x-o->x)*o->aistate()/o->aitype();
959      obj->y=d->y-(d->y-o->y)*o->aistate()/o->aitype();
960    }
961  }
962  return true_symbol;
963}
964
965
966void *respawn_ai()
967{
968 game_object *o=current_object;
969 int x=o->total_objects();
970 if (x)
971 {
972   game_object *last=o->get_object(x-1);
973   if (last->x==o->x && last->y==o->y)
974   {
975     if (last->fade_count())
976       last->set_fade_count(last->fade_count()-1);
977     o->set_aistate_time(0);
978   } else if (o->aistate_time()>o->xvel())
979   {
980     int type=o->get_object(jrandom(x))->otype;
981     game_object *n=create(type,o->x,o->y);
982     current_level->add_object(n);
983     o->add_object(n);
984     n->set_fade_count(15);
985     o->set_aistate_time(0);
986   }
987 }
988 return true_symbol;
989}
990
991static int compare_players(const void *a, const void *b)
992{
993  if  ( ((view **)a)[0]->kills > ((view **)b)[0]->kills)
994    return -1;
995  else if  ( ((view **)a)[0]->kills < ((view **)b)[0]->kills)
996    return 1;
997  else if (((view **)a)[0]->player_number > ((view **)b)[0]->player_number)
998    return -1;
999  else if (((view **)a)[0]->player_number < ((view **)b)[0]->player_number)
1000    return 1;
1001  else return 0;
1002}
1003
1004void *score_draw()
1005{
1006  view *sorted_players[16],*local=NULL;
1007  int tp=0;
1008  view *f=player_list;
1009  for (; f; f=f->next)
1010  {
1011    sorted_players[tp]=f;
1012    tp++;
1013    if (f->local_player()) local=f;
1014  }
1015
1016  JCFont *fnt=wm->font();
1017  if (local)
1018  {
1019    qsort(sorted_players,tp,sizeof(view *),compare_players);
1020
1021    int x=local->cx1;
1022    int y=local->cy1;
1023    char msg[100];
1024
1025    int i;
1026    for (i=0; i<tp; i++)
1027    {
1028      int color=lnumber_value(((LArray *)((LSymbol *)l_player_text_color)->GetValue())->Get(sorted_players[i]->get_tint()));
1029      sprintf(msg,"%3ld %s",(long)sorted_players[i]->kills,sorted_players[i]->name);
1030      if (sorted_players[i]==local)
1031        strcat(msg," <<");
1032
1033      fnt->put_string(screen,x,y,msg,color);
1034      y+=fnt->height();
1035    }
1036  }
1037  return NULL;
1038}
1039
1040
1041extern void fade_in(image *im, int steps);
1042extern void fade_out(int steps);
1043
1044void *show_kills()
1045{
1046  fade_out(8);
1047  wm->set_mouse_position(0,0);
1048  screen->clear();
1049  image *im=cache.img(cache.reg("art/frame.spe","end_level_screen",SPEC_IMAGE,1));
1050  im->put_image(screen,0,0);
1051  int x1=im->Size().x+1,y1=0,y2=screen->Size().y;
1052  JCFont *fnt=wm->font();
1053
1054  view *v=player_list; int tp=0,i;
1055  for (v=player_list; v; v=v->next) tp++;
1056
1057  int y=(y1+y2)/2-(tp+2)*fnt->height()/2,x=x1+10;
1058  char const *header_str = symbol_str("score_header");
1059  fnt->put_string(screen,x,y,header_str,wm->bright_color());
1060  y+=fnt->height();
1061
1062  screen->widget_bar(x,y+2,x+strlen(header_str)*fnt->width(),y+fnt->height()-3,
1063             wm->bright_color(),wm->medium_color(),wm->dark_color());
1064  y+=fnt->height();
1065  v=player_list;
1066  for (i=0; i<tp; i++)
1067  {
1068    enum { NAME_LEN=18 } ;
1069    int color=lnumber_value(((LArray *)((LSymbol *)l_player_text_color)->GetValue())->Get(v->get_tint()));
1070    char max_name[NAME_LEN];
1071    strncpy(max_name,v->name,NAME_LEN-1);
1072    max_name[NAME_LEN-1]=0;
1073    char msg[100];
1074
1075
1076    sprintf(msg,"%-17s %3ld  %3ld",max_name,(long)v->kills,(long)(v->tkills+v->kills));
1077    fnt->put_string(screen,x,y,msg,color);
1078
1079    y+=fnt->height();
1080    v=v->next;
1081  }
1082
1083  wm->flush_screen();
1084  Timer now; now.WaitMs(4000);   // wait 4 seconds
1085
1086  return NULL;
1087}
1088
1089
Note: See TracBrowser for help on using the repository browser.