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

Last change on this file since 655 was 655, checked in by Sam Hocevar, 12 years ago

imlib: refactor a few image methods so that they use vec2i.

File size: 27.8 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      main_screen->PutImage(cache.img(S_health_image),
832                            vec2i(o->controller()->cx2-20,
833                                  o->controller()->cy1+5), 1);
834      } break;
835      case FAST_POWER :
836      {
837    ((LSymbol *)l_draw_fast)->EvalFunction(NULL);
838    int old_state=o->state;
839    switch (o->state)
840    {
841      case stopped : o->state=(character_state)S_fast_stopped; break;
842      case running : o->state=(character_state)S_fast_running; break;
843      case start_run_jump : o->state=(character_state)S_fast_start_run_jump; break;
844      case run_jump : o->state=(character_state)S_fast_run_jump; break;
845      case run_jump_fall : o->state=(character_state)S_fast_run_jump_fall; break;
846      case end_run_jump : o->state=(character_state)S_fast_end_run_jump; break;
847      default: break;
848    }
849
850    player_draw(just_fired,o->get_tint());
851    o->state=(character_state)old_state;
852    if (o->controller() && o->controller()->local_player())
853      main_screen->PutImage(cache.img(S_fast_image),
854                            vec2i(o->controller()->cx2-20,
855                                  o->controller()->cy1+5), 1);
856      } break;
857      case FLY_POWER :
858      {
859    int old_state=o->state;
860    switch (o->state)
861    {
862      case stopped : o->state=(character_state)S_fly_stopped; break;
863      case running : o->state=(character_state)S_fly_running; break;
864      case start_run_jump : o->state=(character_state)S_fly_start_run_jump; break;
865      case run_jump : o->state=(character_state)S_fly_run_jump; break;
866      case run_jump_fall : o->state=(character_state)S_fly_run_jump_fall; break;
867      case end_run_jump : o->state=(character_state)S_fly_end_run_jump; break;
868      default: break;
869    }
870
871    player_draw(just_fired,o->get_tint());
872    o->state=(character_state)old_state;
873
874    if (o->controller() && o->controller()->local_player())
875      main_screen->PutImage(cache.img(S_fly_image),
876                            vec2i(o->controller()->cx2-20,
877                                  o->controller()->cy1+5), 1);
878      } break;
879      case SNEAKY_POWER :
880      {
881    if (o->lvars[used_special_power]==0)
882      player_draw(just_fired,o->get_tint());
883    else if (o->lvars[used_special_power]<15)
884      o->draw_trans(o->lvars[used_special_power],16);
885    else
886      o->draw_predator();
887
888    if (o->controller() && o->controller()->local_player())
889      main_screen->PutImage(cache.img(S_sneaky_image),
890                            vec2i(o->controller()->cx2-20,
891                                  o->controller()->cy1+5), 1);
892      } break;
893    }
894  }
895  return NULL;
896}
897
898
899
900void *sgun_ai()
901{
902  game_object *o=current_object;
903
904  if (o->lvars[sgb_lifetime]==0)
905    return NULL;
906  o->lvars[sgb_lifetime]--;
907
908  o->lvars[sgb_lastx]=o->x;
909  o->lvars[sgb_lasty]=o->y;
910  o->lvars[sgb_speed]=o->lvars[sgb_speed]*6/5;
911
912  int32_t ang=o->lvars[sgb_angle];
913  int32_t mag=o->lvars[sgb_speed];
914
915  int32_t xvel=(lisp_cos(ang))*(mag);
916  current_object->set_xvel(xvel>>16);
917  current_object->set_fxvel((xvel&0xffff)>>8);
918  int32_t yvel=-(lisp_sin(ang))*(mag);
919  current_object->set_yvel(yvel>>16);
920  current_object->set_fyvel((yvel&0xffff)>>8);
921
922
923  int whit=0;
924  game_object *who=o->bmove(whit, o->total_objects() ? o->get_object(0) : 0);
925
926  if (whit || (who && figures[who->otype]->get_cflag(CFLAG_UNACTIVE_SHIELD) && who->total_objects() &&
927           who->get_object(0)->aistate()==0))
928  {
929    o->lvars[sgb_lifetime]=0;
930    game_object *n=create(S_EXPLODE5,o->x+jrand()%4,o->y+jrand()%4);
931    current_level->add_object(n);
932  } else if (who && figures[who->otype]->get_cflag(CFLAG_HURTABLE))
933  {
934    o->lvars[sgb_lifetime]=0;
935    game_object *n=create(S_EXPLODE3,o->x+jrand()%4,o->y+jrand()%4);
936    current_level->add_object(n);
937     who->do_damage(5,o,o->x,o->y,(lisp_cos(ang)*10)>>16,(lisp_sin(ang)*10)>>16);
938  }
939  return true_symbol;
940}
941
942
943
944void *mover_ai()
945{
946  game_object *o=current_object;
947  if (o->total_objects()==2)
948  {
949    if (o->aistate()<2)
950    {
951      game_object *obj=o->get_object(1);
952      o->remove_object(obj);
953      game_object *d=o->get_object(0);
954      d->add_object(obj);
955      d->set_aistate(d->aitype());
956    } else
957    {
958      o->set_aistate(o->aistate()-1);
959      game_object *d=o->get_object(0);
960      game_object *obj=o->get_object(1);
961
962      obj->x=d->x-(d->x-o->x)*o->aistate()/o->aitype();
963      obj->y=d->y-(d->y-o->y)*o->aistate()/o->aitype();
964    }
965  }
966  return true_symbol;
967}
968
969
970void *respawn_ai()
971{
972 game_object *o=current_object;
973 int x=o->total_objects();
974 if (x)
975 {
976   game_object *last=o->get_object(x-1);
977   if (last->x==o->x && last->y==o->y)
978   {
979     if (last->fade_count())
980       last->set_fade_count(last->fade_count()-1);
981     o->set_aistate_time(0);
982   } else if (o->aistate_time()>o->xvel())
983   {
984     int type=o->get_object(jrandom(x))->otype;
985     game_object *n=create(type,o->x,o->y);
986     current_level->add_object(n);
987     o->add_object(n);
988     n->set_fade_count(15);
989     o->set_aistate_time(0);
990   }
991 }
992 return true_symbol;
993}
994
995static int compare_players(const void *a, const void *b)
996{
997  if  ( ((view **)a)[0]->kills > ((view **)b)[0]->kills)
998    return -1;
999  else if  ( ((view **)a)[0]->kills < ((view **)b)[0]->kills)
1000    return 1;
1001  else if (((view **)a)[0]->player_number > ((view **)b)[0]->player_number)
1002    return -1;
1003  else if (((view **)a)[0]->player_number < ((view **)b)[0]->player_number)
1004    return 1;
1005  else return 0;
1006}
1007
1008void *score_draw()
1009{
1010  view *sorted_players[16],*local=NULL;
1011  int tp=0;
1012  view *f=player_list;
1013  for (; f; f=f->next)
1014  {
1015    sorted_players[tp]=f;
1016    tp++;
1017    if (f->local_player()) local=f;
1018  }
1019
1020  JCFont *fnt=wm->font();
1021  if (local)
1022  {
1023    qsort(sorted_players,tp,sizeof(view *),compare_players);
1024
1025    int x=local->cx1;
1026    int y=local->cy1;
1027    char msg[100];
1028
1029    int i;
1030    for (i=0; i<tp; i++)
1031    {
1032      int color=lnumber_value(((LArray *)((LSymbol *)l_player_text_color)->GetValue())->Get(sorted_players[i]->get_tint()));
1033      sprintf(msg,"%3ld %s",(long)sorted_players[i]->kills,sorted_players[i]->name);
1034      if (sorted_players[i]==local)
1035        strcat(msg," <<");
1036
1037      fnt->put_string(main_screen,x,y,msg,color);
1038      y+=fnt->height();
1039    }
1040  }
1041  return NULL;
1042}
1043
1044
1045extern void fade_in(image *im, int steps);
1046extern void fade_out(int steps);
1047
1048void *show_kills()
1049{
1050  fade_out(8);
1051  wm->set_mouse_position(0,0);
1052  main_screen->clear();
1053  image *im=cache.img(cache.reg("art/frame.spe","end_level_screen",SPEC_IMAGE,1));
1054  main_screen->PutImage(im, vec2i(0, 0));
1055  int x1=im->Size().x+1,y1=0,y2=main_screen->Size().y;
1056  JCFont *fnt=wm->font();
1057
1058  view *v=player_list; int tp=0,i;
1059  for (v=player_list; v; v=v->next) tp++;
1060
1061  int y=(y1+y2)/2-(tp+2)*fnt->height()/2,x=x1+10;
1062  char const *header_str = symbol_str("score_header");
1063  fnt->put_string(main_screen,x,y,header_str,wm->bright_color());
1064  y+=fnt->height();
1065
1066  main_screen->WidgetBar(vec2i(x, y + 2),
1067                         vec2i(x + strlen(header_str) * fnt->width(),
1068                               y + fnt->height() - 3),
1069                         wm->bright_color(), wm->medium_color(),
1070                         wm->dark_color());
1071  y+=fnt->height();
1072  v=player_list;
1073  for (i=0; i<tp; i++)
1074  {
1075    enum { NAME_LEN=18 } ;
1076    int color=lnumber_value(((LArray *)((LSymbol *)l_player_text_color)->GetValue())->Get(v->get_tint()));
1077    char max_name[NAME_LEN];
1078    strncpy(max_name,v->name,NAME_LEN-1);
1079    max_name[NAME_LEN-1]=0;
1080    char msg[100];
1081
1082
1083    sprintf(msg,"%-17s %3ld  %3ld",max_name,(long)v->kills,(long)(v->tkills+v->kills));
1084    fnt->put_string(main_screen,x,y,msg,color);
1085
1086    y+=fnt->height();
1087    v=v->next;
1088  }
1089
1090  wm->flush_screen();
1091  Timer now; now.WaitMs(4000);   // wait 4 seconds
1092
1093  return NULL;
1094}
1095
1096
Note: See TracBrowser for help on using the repository browser.