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

Last change on this file since 527 was 527, checked in by Sam Hocevar, 10 years ago

imlib: some cleaning up in trans_image before I templatise half of it.

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