source: abuse/trunk/src/level.cpp @ 2

Last change on this file since 2 was 2, checked in by Sam Hocevar, 14 years ago
  • imported original 0.7.0 tarball
File size: 72.4 KB
Line 
1#include "light.hpp"
2#include "level.hpp"
3#include "game.hpp"
4#include "intsect.hpp"
5#include "lisp.hpp"
6#include "dprint.hpp"
7#include "particle.hpp"
8#include "objects.hpp"
9#include "jrand.hpp"
10#include "macs.hpp"
11#include "clisp.hpp"
12#include "status.hpp"
13#include "dev.hpp"
14#include "demo.hpp"
15#include "pcxread.hpp"
16#include "profile.hpp"
17#include "sbar.hpp"
18#include "cop.hpp"
19#include "nfserver.hpp"
20#include "lisp_gc.hpp"
21
22#if (defined(__MACH__) || !defined(__APPLE__))
23#include <sys/stat.h>
24#endif
25
26#include <time.h>
27
28level *current_level;
29
30game_object *level::attacker(game_object *who)
31{
32  long d=0x7fffffff;
33  game_object *c=NULL;
34  view *f=the_game->first_view;
35  for (;f;f=f->next)
36  {
37    if (f->focus)
38    {
39      long tmp_d=abs(f->focus->x-who->x)+abs(f->focus->y-who->y);
40      if (tmp_d<d)
41      {
42        d=tmp_d;
43        c=f->focus;
44      }
45    }
46  }
47  CONDITION(c,"no attacker found");
48  return c;
49}
50
51
52
53int level::is_attacker(game_object *who)
54{
55  return who->controller()!=NULL;
56}
57
58
59game_object *level::main_character()
60{
61  return the_game->first_view->focus;
62}
63
64void level::load_fail()
65{
66  if (map_fg)    jfree(map_fg);   map_fg=NULL;
67  if (map_bg)    jfree(map_bg);   map_bg=NULL;
68  if (Name)      jfree(Name);     Name=NULL;
69
70  first_active=NULL;
71  view *f=player_list;
72  for (;f;f=f->next)
73    if (f->focus)
74      current_level->remove_object(f->focus);
75
76  while (first)
77  {
78    first_active=first;
79    first=first->next;
80    if (dev_cont)
81      dev_cont->notify_deleted_object(first_active);
82    delete first_active;
83  }
84
85  while (area_list)
86  {
87    area_controller *l=area_list;
88    area_list=area_list->next;
89    delete l;
90  }
91
92  last=NULL;
93  delete_panims();
94  delete_all_lights();
95
96}
97
98level::~level()
99{
100  load_fail();
101  if (attack_list) jfree(attack_list);
102  if (target_list) jfree(target_list);
103  if (block_list) jfree(block_list);
104  if (all_block_list) jfree(all_block_list);
105  if (first_name) jfree(first_name);
106}
107
108void level::restart()
109{
110  view *f;
111  game_object *found=NULL,*o;
112  f=the_game->first_view;
113  for (o=first;f && o;o=o->next)
114  {
115    while (f && !f->focus) f=f->next;
116    if (f)
117    {
118      if (!strcmp(object_names[o->otype],"START"))
119      {
120        if (!found) found=o;
121        f->focus->x=o->x;
122        f->focus->y=o->y;         
123        f->focus->set_hp(get_ability(f->focus->otype,start_hp));
124        f->focus->set_state(stopped);
125        f=f->next;
126      }
127    }
128  }
129  while (f)
130  {
131    if (f->focus)
132    {
133      f->focus->x=found->x;
134      f->focus->y=found->y;         
135      f->focus->set_hp(get_ability(f->focus->otype,start_hp));
136      f->focus->set_state(stopped);     
137    }
138    f=f->next;
139  }
140}
141
142
143void level::next_focus()
144{
145/*  int i;
146  for (i=0;i<total_objs;i++)
147    if (obj[i]==the_game->first_view->focus)
148    {     
149      int tries=total_objs;
150      do
151      {
152        i++;
153        if (i==total_objs)
154          i=0;
155        the_game->first_view->focus=obj[i];
156      }  while ((!the_game->first_view->focus->is_playable() ||
157                 the_game->first_view->focus->hp<=0) && tries--);
158      return ;
159    }         */ 
160}
161
162void level::unactivate_all()
163{
164  first_active=NULL;
165  game_object *o=first;
166  attack_total=0;  // reset the attack list
167  target_total=0;
168  block_total=0;
169  all_block_total=0;
170
171  for (;o;o=o->next)
172    o->active=0;
173}
174
175
176void level::pull_actives(game_object *o, game_object *&last_active, int &t)
177{
178  int i=o->total_objects();
179  for (;i;i--)        // pull any linked object into active list
180  {
181    game_object *other=o->get_object(i-1);
182    if (!other->active)
183    {
184      other->active=1;
185      if (other->can_block())              // if object can block other player, keep a list for fast testing
186      {
187        add_block(other);
188        add_all_block(other);
189      } else if (other->hurtable())
190        add_all_block(other);
191
192      t++;
193      last_active->next_active=other;
194      last_active=other;       
195      pull_actives(o,last_active,t);
196    }
197  }
198}
199
200int level::add_actives(long x1, long y1, long x2, long y2)
201{
202  int t=0;
203  game_object *last_active=NULL;
204  if (first_active)
205    for (last_active=first_active;last_active->next_active;last_active=last_active->next_active);
206
207  game_object *o=first;
208  for (;o;o=o->next)
209  {   
210    if (!o->active)
211    {
212      long xr=figures[o->otype]->rangex,
213           yr=figures[o->otype]->rangey;
214
215      if (o->x+xr>=x1 && o->x-xr<=x2 && o->y+yr>=y1 && o->y-yr<=y2)
216      {
217       
218        if (o->can_block())              // if object can block other player, keep a list for fast testing
219        {
220          add_block(o);
221          add_all_block(o);
222        } else if (o->hurtable())
223          add_all_block(o);
224     
225
226        o->active=1;
227        t++;
228        if (!first_active)     
229          first_active=o;       
230        else
231          last_active->next_active=o;
232        last_active=o;
233
234        pull_actives(o,last_active,t); 
235      } 
236    } 
237  }
238  if (last_active)
239    last_active->next_active=NULL;
240  return t;
241}
242
243
244int level::add_drawables(long x1, long y1, long x2, long y2)
245{
246  int t=0,ft=0;
247  game_object *last_active=NULL;
248  if (first_active)
249  {
250    for (last_active=first_active;last_active->next_active;last_active=last_active->next_active);
251  } else ft=1;
252
253  game_object *o=first;
254  for (;o;o=o->next)
255  {   
256    if (ft || !o->active)
257    {
258      long xr=figures[o->otype]->draw_rangex,
259      yr=figures[o->otype]->draw_rangey;
260
261      if (o->x+xr>=x1 && o->x-xr<=x2 && o->y+yr>=y1 && o->y-yr<=y2)
262      {
263        t++;
264        if (!first_active)     
265        first_active=o;
266        else
267        last_active->next_active=o;
268        last_active=o;
269        o->active=1;
270      } else if (ft) o->active=0;  // if this is the first pass, then mark objects not in this ranges as not active
271    }
272  }
273  if (last_active)
274    last_active->next_active=NULL;
275  return t;
276}
277
278
279view *level::make_view_list(int nplayers)
280{
281  int startable;
282  CONDITION(nplayers>0,"make_view_list with <=0 players!\n");
283  view *f=NULL;
284  int j,use_type=current_start_type;
285  figures[use_type]->cache_in();
286  game_object *o,*last_start=NULL;
287  int num=0;
288 
289  for (j=0,o=first;o && j<nplayers;o=o->next)
290  {
291    if (!strcmp(object_names[o->otype],"START"))
292    {
293      f=new view(create(use_type,o->x,o->y),f,num); num++;
294      f->focus->set_controller(f);
295      add_object_after(f->focus,o);
296      j++;
297      last_start=o;
298    }
299  }
300 
301  // if we couldn't find enough starts then create the rest of the players at the original start
302  startable=j;  // if we haven't created anyone yet, it's because we can't
303
304  for (;j<nplayers;j++)
305  {
306    if (startable)
307    {
308      game_object *o=create(use_type,f->focus->x,f->focus->y);
309      f=new view(o,f,num); num++;
310      f->focus->set_controller(f);
311      add_object_after(o,last_start);
312    }
313    else
314    {
315      f=new view(NULL,f,num);
316      num++;
317    }
318  }
319  return f;
320}
321
322void level::wall_push()
323{
324  long sx1,sy1,sx2,sy2,xv,yv;
325  game_object *o=first_active;
326  for (;o;o=o->next_active)
327  {
328    if (o->pushable())
329    {
330      o->picture_space(sx1,sy1,sx2,sy2);
331      xv=sx1-o->x;
332      yv=0;
333      o->try_move(o->x,o->y-1,xv,yv,1);         // check for wall pushes on the left using feet
334      if (xv!=sx1-o->x)                         // is the character in the wall?
335      {
336        xv=-xv;
337        o->try_move(o->x,o->y-1,xv,yv,1);       // see how far to the right we can push the character
338        o->x+=xv;
339      } else
340      {
341        xv=sx2-o->x;
342        o->try_move(o->x,o->y-1,xv,yv,1);      // now check the right of the character for a wall
343        if (xv!=sx2-o->x)
344        {
345          xv=-xv;
346          o->try_move(o->x,o->y-1,xv,yv,1);
347          o->x+=xv;
348        }
349      }           
350    }
351  }
352}
353
354
355void level::try_pushback(game_object *subject,game_object *target)
356{
357  if (subject->pushable() && target->pushable() &&
358      subject->state!=dead && target->state!=dead &&
359      subject->state!=dieing && target->state!=dieing)
360  {
361    int b1=subject->push_range(),b2=target->push_range();
362    if (abs(subject->x-target->x)<b1+b2)
363    {
364      long tmove=b1+b2-abs(subject->x-target->x),xv,yv=0,xv2;
365      if (subject->x>target->x)
366        xv=tmove/2;
367      else xv=-tmove/2;
368      xv2=-xv;
369
370      subject->try_move(subject->x,subject->y,xv,yv,3);
371      subject->x+=xv;
372
373      yv=0;
374      target->try_move(target->x,target->y,xv2,yv,3);
375      target->x+=xv2;     
376    }
377  }
378}
379
380/*
381void level::check_collisions()
382{
383  game_object *target,*reciever=NULL;
384  long sx1,sy1,sx2,sy2,tx1,ty1,tx2,ty2,hitx,hity,
385      s_centerx,t_centerx;
386
387  for (game_object *subject=first_active;subject;subject=subject->next_active)
388  {
389    subject->picture_space(sx1,sy1,sx2,sy2);   
390    s_centerx=subject->x_center();
391
392    int hit=0;
393    reciever=NULL;
394    for (target=first_active;target;target=target->next_active)
395    {
396      if (target!=subject)
397      {
398        target->picture_space(tx1,ty1,tx2,ty2);
399
400        if (!(sx2<tx1 || sx1>tx2 || sy1>ty2 || sy2<ty1))  // are they semi/overlapping?
401        {   
402          try_pushback(subject,target);
403          if (subject->can_hurt(target))    // see if we can hurt him before calculating
404          {         
405            t_centerx=target->x_center();
406            point_list *s_hit,*t_damage;
407                         
408            s_hit=subject->current_figure()->hit;         
409            t_damage=target->current_figure()->damage;
410
411            unsigned char *s_dat=s_hit->data,
412            *t_dat;
413            int i,j;
414            for (i=(int)s_hit->tot-1;i>0 && !hit;i--)
415            {
416              for (t_dat=t_damage->data,j=(int)t_damage->tot-1;j>0 && !hit;j--)
417              {
418                long x1,y1,x2,y2,          // define the two line segments to check
419                xp1,yp1,xp2,yp2;
420
421                xp1=target->x+target->tx(*t_dat);  t_dat++;           
422                yp1=target->y+target->ty(*t_dat);  t_dat++;
423                xp2=target->x+target->tx(*t_dat);
424                yp2=target->y+target->ty(t_dat[1]);
425
426                x1=subject->x+subject->tx(s_dat[0]); 
427                y1=subject->y+subject->ty(s_dat[1]);
428                x2=subject->x+subject->tx(s_dat[2]);
429                y2=subject->y+subject->ty(s_dat[3]);
430             
431
432                // ok, now we know which line segemnts to check for intersection
433                // now check to see if (x1,y1-x2,y2) intercest with (xp1,yp1-xp2,yp2)
434                int _x2=x2,_y2=y2;           
435                setback_intersect(x1, y1, x2, y2, xp1, yp1, xp2, yp2,0);
436
437
438                if (x2!=_x2 || _y2!=y2)
439                {
440                  reciever=target;
441                  hitx=((x1+x2)/2+(xp1+xp2)/2)/2;
442                  hity=((y1+y1)/2+(yp1+yp2)/2)/2;
443                }
444              }
445              s_dat+=2;
446            }       
447          }
448        }
449      } 
450    }   
451    if (reciever)
452    {
453      reciever->do_damage((int)subject->current_figure()->hit_damage,subject,hitx,hity,0,0);
454      subject->note_attack(reciever);
455      hit=1;
456    }
457  }
458}
459*/
460
461game_object *level::boundary_setback(game_object *subject, long x1, long y1, long &x2, long &y2)
462{
463  game_object *l=NULL;
464  long tx1,ty1,tx2,ty2,t_centerx;
465  game_object *target=first_active;
466  game_object **blist=block_list;
467  int t=block_total;
468  for (;t;t--,blist++)
469  {
470    target=*blist;
471    if (target!=subject && (target->total_objects()==0 || target->get_object(0)!=subject))
472    {
473      target->picture_space(tx1,ty1,tx2,ty2);
474      if (!((x2<tx1 && x1<tx1) || (x1>tx2 && x2>tx2) ||
475            (y1>ty2 && y2>ty2) || (y1<ty1 && y2<ty1)))  // are they semi/overlapping?
476      {         
477        t_centerx=target->x_center();
478        boundary *t_damage;
479        if (target->direction>0)
480        t_damage=target->current_figure()->f_damage;
481        else
482        t_damage=target->current_figure()->b_damage;
483        unsigned char *t_dat=t_damage->data,*ins=t_damage->inside;
484        int iter=t_damage->tot-1;
485        while(iter-->0)
486        {
487          long xp1=target->x+target->tx(*t_dat);  t_dat++;           
488          long yp1=target->y+target->ty(*t_dat);  t_dat++;
489          long xp2=target->x+target->tx(*t_dat);
490          long yp2=target->y+target->ty(t_dat[1]);
491
492          // now check to see if (x1,y1-x2,y2) intercest with (xp1,yp1-xp2,yp2)
493          if (*ins)
494          {               
495            if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,1))
496            l=target;
497          }         
498          else
499          {
500            if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,-1))
501            l=target;
502          }         
503          ins++;
504         
505        }         
506      }     
507    }   
508  }
509  return l;       // return the last person we intersected 
510}
511
512
513game_object *level::all_boundary_setback(game_object *subject, long x1, long y1, long &x2, long &y2)
514{
515  game_object *l=NULL;
516  long tx1,ty1,tx2,ty2,t_centerx;
517  game_object *target=first_active;
518  game_object **blist=all_block_list;
519  int t=all_block_total;
520  for (;t;t--,blist++)
521  {
522    target=*blist;
523    if (target!=subject && (target->total_objects()==0 || target->get_object(0)!=subject))
524    {
525      target->picture_space(tx1,ty1,tx2,ty2);
526      if (!((x2<tx1 && x1<tx1) || (x1>tx2 && x2>tx2) ||
527            (y1>ty2 && y2>ty2) || (y1<ty1 && y2<ty1)))  // are they semi/overlapping?
528      {         
529        t_centerx=target->x_center();
530        boundary *t_damage;
531        if (target->direction>0)
532        t_damage=target->current_figure()->f_damage;
533        else
534        t_damage=target->current_figure()->b_damage;
535        unsigned char *t_dat=t_damage->data,*ins=t_damage->inside;
536        int iter=t_damage->tot-1;
537        while(iter-->0)
538        {
539          long xp1=target->x+target->tx(*t_dat);  t_dat++;           
540          long yp1=target->y+target->ty(*t_dat);  t_dat++;
541          long xp2=target->x+target->tx(*t_dat);
542          long yp2=target->y+target->ty(t_dat[1]);
543
544          // now check to see if (x1,y1-x2,y2) intercest with (xp1,yp1-xp2,yp2)
545          if (*ins)
546          {               
547            if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,1))
548            l=target;
549          }         
550          else
551          {
552            if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,-1))
553            l=target;
554          }         
555          ins++;         
556        }         
557      }     
558    }   
559  }
560  return l;       // return the last person we intersected 
561}
562
563
564//bFILE *rcheck=NULL,*rcheck_lp=NULL;
565
566void level::interpolate_draw_objects(view *v)
567{
568  long old_x,old_y;
569  current_view=v;
570 
571  game_object *o=first_active;
572  for (;o;o=o->next_active)
573  {
574    old_x=o->x;
575    old_y=o->y;
576    o->x=(o->last_x+o->x)/2;
577    o->y=(o->last_y+o->y)/2;
578    o->last_x=old_x;
579    o->last_y=old_y;
580  }
581
582  for (o=first_active;o;o=o->next_active)
583    o->draw();
584
585  for (o=first_active;o;o=o->next_active)
586  {
587    o->x=o->last_x;
588    o->y=o->last_y;
589  }
590}
591
592bFILE *rcheck=NULL,*rcheck_lp=NULL;
593
594extern int sshot_fcount,screen_shot_on;
595
596int level::tick()
597{
598  game_object *o,*l=NULL,  // l is last, used for delete
599              *cur;        // cur is current object, NULL if object deletes it's self
600  int ret=1;
601
602  if (profiling())
603    profile_reset();
604
605/*  // test to see if demo is in sync
606  if (current_demo_mode()==DEMO_PLAY)
607  {
608    if (!rcheck) rcheck=open_file("rcheck","rb");
609    long x=rcheck->read_long();
610    if (x!=rand_on)
611      dprintf("off!\n");
612  } else if (current_demo_mode()==DEMO_RECORD)
613  {
614    if (!rcheck)
615    {
616      rcheck=open_file("rcheck","wb");
617      rcheck_lp=open_file("rcheck.lp","wb");
618    }
619    rcheck->write_long(rand_on);
620  } else
621  {
622    if (rcheck)
623    {
624      delete rcheck;
625      rcheck=NULL;
626    }
627    if (rcheck_lp)
628    {
629      delete rcheck_lp;
630      rcheck_lp=NULL;
631    }
632  }*/
633 
634  for (o=first_active;o;)
635  {       
636    o->last_x=o->x;
637    o->last_y=o->y;
638    cur=o;
639    view *c=o->controller();
640    if (!(dev&SUSPEND_MODE) || c)
641    {
642      o->set_flags(o->flags()&(0xff-FLAG_JUST_HIT-FLAG_JUST_BLOCKED));
643
644      if (c)
645      {     
646        area_controller *a,*smallest=NULL;
647        long smallest_size=0xfffffff;
648        for (a=area_list;a;a=a->next)
649          if (o->x>=a->x && o->y>=a->y && o->x<=a->x+a->w && o->y<=a->y+a->h)
650          {
651            long size=a->w*a->h;
652            if (size<smallest_size)
653            {
654              smallest=a;
655              smallest_size=size;
656            }
657          }
658
659        if (c->local_player())
660        {
661          if (!shutdown_lighting)       // should we initiate a lighting shutdown?
662          {
663            if (massive_frame_panic>30)
664            {
665              shutdown_lighting=100;
666              shutdown_lighting_value=c->ambient;
667            }
668          } else if (massive_frame_panic)  // do we need brighten towards 63?
669          {
670            if (shutdown_lighting_value<63)
671              shutdown_lighting_value++;
672          } else if (shutdown_lighting>1)        // delay for some time before turning back on
673            shutdown_lighting--;
674          else if (shutdown_lighting_value!=c->ambient) // do we need to lower light toward real ambient?
675          {
676            if (abs(shutdown_lighting_value-c->ambient)<4)
677              shutdown_lighting_value=c->ambient;
678            else
679              if (shutdown_lighting_value<c->ambient)
680                shutdown_lighting_value+=4;
681            else if (shutdown_lighting_value>c->ambient)
682              shutdown_lighting_value-=4;
683          } else shutdown_lighting=0;                    // back to normal
684        }
685
686        if (smallest)
687          c->configure_for_area(smallest);
688
689
690        o->move(c->x_suggestion,c->y_suggestion,c->b1_suggestion|(c->b2_suggestion<<1)|
691                (c->b3_suggestion<<2));
692
693        if (o->otype!=current_start_type)
694        {
695          long fmp=o->fmp();     
696          int reduce=figures[o->otype]->morph_power;
697          if (reduce)
698          {
699            fmp-=reduce;
700            o->add_power(fmp>>16);
701            o->set_fmp(fmp&0xffff);
702            if (o->mp()<=0)
703            o->morph_into(current_start_type,NULL,-1,9);
704          }
705        }
706
707        l=o;
708        o=o->next_active;       
709      }
710      else if (!o->decide())      // if object returns 0, delete it... I don't like 0's :)
711      {
712        game_object *p=o;
713        o=o->next_active;
714        delete_object(p);
715        cur=NULL;
716      } else
717      {
718        o=o->next_active;
719        l=o;
720      }
721    } else
722    {
723      o=o->next_active;
724      l=o;     
725    }
726
727    clear_tmp();
728
729    if (cur)
730    {
731      point_list *p=cur->current_figure()->hit;  // see if this character is on an attack frame
732      if (p && p->tot)
733        add_attacker(cur);               // if so add him to attack list for later collision detect
734     
735      if (cur->hurtable())                    // add to target list if is hurtable
736        add_target(cur);
737     
738    }
739
740  }
741  tick_panims();
742
743  check_collisions();
744//  wall_push();
745
746  set_tick_counter(tick_counter()+1);
747
748  if (sshot_fcount!=-1)
749  {
750    sshot_fcount++;
751    if ((sshot_fcount%70)==0)
752    {   
753      char name[100];
754      sprintf(name,"shot%04d.pcx",screen_shot_on++);
755      write_PCX(screen,pal,name);
756    }
757  }
758
759  return ret;
760}
761
762void level::set_tick_counter(ulong x)
763{
764  ctick=x;
765}
766
767void level::draw_areas(view *v)
768{
769  long sx1,sy1,sx2,sy2;
770  area_controller *a=area_list;
771  for (;a;a=a->next)
772  {
773    int c1,c2;
774    if (a->active)
775    {
776      c1=morph_sel_frame_color;
777      c2=eh->bright_color();
778    } else
779    {
780      c2=morph_sel_frame_color;
781      c1=eh->bright_color();
782    }
783   
784    the_game->game_to_mouse(a->x,a->y,v,sx1,sy1);
785    the_game->game_to_mouse(a->x+a->w,a->y+a->h,v,sx2,sy2);
786    screen->rectangle(sx1,sy1,sx2,sy2,c1);
787    screen->bar(sx1-1,sy1-1,sx1+1,sy1+1,c2);
788    screen->bar(sx2-1,sy2-1,sx2+1,sy2+1,c2);
789  }
790}
791
792void level::draw_objects(view *v)
793{
794  current_view=v;
795  game_object *o=first_active;
796  if (dev&MAP_MODE)
797  {
798    for (;o;o=o->next_active)
799      o->map_draw();
800  } else
801  {
802    for (;o;o=o->next_active)
803      o->draw();
804  }
805
806  clear_tmp();
807
808
809void calc_bgsize(unsigned short fgw, unsigned short  fgh, unsigned short  &bgw, unsigned short  &bgh)
810{
811  bgw=fgw/ASPECT+8;
812  bgh=fgh/ASPECT+8; 
813}
814
815
816void level::set_size(int w, int h)
817{
818  if (w*h>200000)
819  {
820    the_game->show_help(symbol_str("too_big"));
821    return ;
822  }
823
824  unsigned short *new_fg,*new_bg;
825  new_fg=(unsigned short *)jmalloc(w*h*sizeof(short),"Map fg : resized");
826  memset(new_fg,0,w*h*sizeof(short));
827
828  int x,y,miny=(h<fg_height)? h : fg_height,minx=(w<fg_width)? w : fg_width;
829 
830  unsigned short nbw,nbh;
831  calc_bgsize(w,h,nbw,nbh);
832 
833  new_bg=(unsigned short *)jmalloc((int)nbw*(int)nbh*sizeof(short),"map bg : resized");
834  memset(new_bg,0,(int)nbw*(int)nbh*sizeof(short));
835
836  for (y=0;y<miny;y++)
837    for (x=0;x<minx;x++)
838      new_fg[x+y*w]=get_fg(x,y);
839
840  miny=(nbh<bg_height) ? nbh : bg_height;
841  minx=(nbw<bg_width) ? nbw : bg_width;
842
843  for (y=0;y<miny;y++)
844    for (x=0;x<minx;x++)
845      new_bg[x+y*nbw]=get_bg(x,y);
846
847  jfree(map_fg);
848  jfree(map_bg);
849  map_fg=new_fg;
850  map_bg=new_bg;
851  fg_width=w;
852  fg_height=h;
853  bg_height=nbh;
854  bg_width=nbw;
855
856  char msg[80];
857  sprintf(msg,"Level %s size now %d %d\n",name(),foreground_width(),foreground_height());
858  the_game->show_help(msg);
859}
860
861
862int locate_var(bFILE *fp, spec_directory *sd, char *str, int size)
863{
864  spec_entry *se=sd->find(str);
865  if (se)
866  {
867    fp->seek(se->offset,0);
868    if (RC_type_size(fp->read_byte())!=size)
869      return 0;
870    else return 1;
871  }
872  return 0;
873}
874
875
876// load objects assumes current objects have already been disposed of
877void level::old_load_objects(spec_directory *sd, bFILE *fp)
878{
879  spec_entry *se=sd->find("objects");
880  total_objs=0;
881  first=last=first_active=NULL;
882  int i,j;
883  if (se)
884  {
885    fp->seek(se->offset,0);
886    /******************************* Read debug info ******************************/
887    short old_tot=fp->read_short(); 
888    unsigned short *o_remap=(unsigned short *)jmalloc(old_tot*2,"obj remap array");   
889    char old_name[150];     
890    for (i=0;i<old_tot;i++)
891    {
892      fp->read(old_name,fp->read_byte());    // read the name
893      for (o_remap[i]=0xffff,j=0;j<total_objects;j++)  // check for matching current name
894      {
895        if (!strcmp(old_name,object_names[j]))
896          o_remap[i]=j;
897      }
898    }
899
900
901    /***************************** Read state names *********************************/
902    int old_stot=fp->read_short();
903    unsigned char *s_remap=(unsigned char *)jmalloc(old_stot,"state remap array");
904    for (i=0;i<old_stot;i++)
905    {
906      fp->read(old_name,fp->read_byte());
907      s_remap[i]=stopped;           // non exsitant states get mapped into stopped state
908      for (j=0;j<MAX_STATE;j++)                  // see if old state exist now
909        if (!strcmp(state_names[j],old_name))
910         s_remap[i]=j;
911    }
912    total_objs=fp->read_long();   
913
914    se=sd->find("type");
915    if (se)
916    {
917      fp->seek(se->offset,0);
918      last=NULL;
919      if (fp->read_byte()==RC_S)    //  read type array, this should be type RC_S
920      {
921        for (i=0;i<total_objs;i++)
922        {
923          ushort t=fp->read_short();
924          game_object *p=new game_object(o_remap[t],1);
925          clear_tmp();
926          if (!first) first=p; else last->next=p;
927          last=p; p->next=NULL;           
928        }
929
930       
931        se=sd->find("state");
932        if (se)
933        {
934          fp->seek(se->offset,0);
935          if (fp->read_byte()==RC_S)    //  read state array, this should be type RC_S
936          {
937            game_object *l=first;
938            for (i=0;i<total_objs;i++,l=l->next)
939            {
940              character_state s=(character_state)s_remap[fp->read_short()];
941              if (l->otype!=0xffff)
942              {
943                if (l->has_sequence((character_state)s))
944                  l->state=s;
945                else l->state=stopped;
946                l->current_frame=0;
947              }
948            }
949          }
950        }
951
952        int frame_var=0;
953        int i=0;
954        for (;i<TOTAL_OBJECT_VARS;i++)
955          if (!strcmp(object_descriptions[i].name,"cur_frame"))
956            frame_var=i;
957           
958        int j=0;
959        for (;j<default_simple.total_vars();j++)
960        {
961          spec_entry *se=sd->find(object_descriptions[j].name);
962          if (se)
963          {
964            fp->seek(se->offset,0);
965            int t=object_descriptions[j].type;
966            if (fp->read_byte()!=t)
967              dprintf("Warning : load level -> var '%s' size changed\n");
968            else
969            {
970              game_object *f=first;
971              for (;f;f=f->next)
972              {       
973                switch (t)
974                {
975                  case RC_C : f->set_var(j,fp->read_byte()); break;
976                  case RC_S : f->set_var(j,fp->read_short()); break;
977                  case RC_L : f->set_var(j,fp->read_long()); break;
978                }
979
980                // check to make sure the frame number is not out of bounds from the time
981                // it was last saved
982                if (j==frame_var)
983                {
984                  if (f->otype!=0xffff && f->current_frame>=
985                      figures[f->otype]->get_sequence(f->state)->length())
986                    f->current_frame=0;
987                }
988              }
989            }       
990          } else dprintf("Warning : load level -> no previous var %s\n",default_simple.var_name(j));
991        }
992      }
993    }
994   
995   
996
997    jfree(o_remap);
998    jfree(s_remap);
999  } 
1000 
1001}
1002
1003
1004// load objects assumes current objects have already been disposed of
1005void level::load_objects(spec_directory *sd, bFILE *fp)
1006{
1007  spec_entry *se=sd->find("object_descripitions");
1008  total_objs=0;
1009  first=last=first_active=NULL;
1010  int i,j;
1011  if (!se)
1012  {
1013    old_load_objects(sd,fp);
1014    return ;
1015  }
1016  else if (se)
1017  {
1018    fp->seek(se->offset,0);
1019    short old_tot=fp->read_short();
1020    se=sd->find("describe_names");
1021    if (!se || !old_tot)
1022      return ;
1023
1024    unsigned short *o_remap=(unsigned short *)jmalloc(old_tot*2,"obj remap array");   
1025    unsigned short *o_backmap=(unsigned short *)jmalloc(total_objects*2,"obj remap array");   
1026    memset(o_backmap,0xff,total_objects*2);
1027    char old_name[150];     
1028    for (i=0;i<old_tot;i++)
1029    {
1030      fp->read(old_name,fp->read_byte());    // read the name
1031      for (o_remap[i]=0xffff,j=0;j<total_objects;j++)  // check for matching current name
1032      {
1033        if (!strcmp(old_name,object_names[j]))
1034        {
1035          o_remap[i]=j;
1036          o_backmap[j]=i;
1037        }
1038      }
1039    }   
1040
1041    se=sd->find("describe_states");
1042    if (!se) { jfree(o_remap); jfree(o_backmap); return ; }
1043    short **s_remap=(short **)jmalloc(old_tot*sizeof(short *),"big state remap array");
1044    short *s_remap_totals=(short *)jmalloc(old_tot*sizeof(short),"big state rmp totals");
1045    fp->seek(se->offset,0);
1046    int i=0;
1047    for (;i<old_tot;i++)
1048    {
1049      short t=fp->read_short();
1050      s_remap_totals[i]=t;
1051      if (t)
1052      {
1053        s_remap[i]=(short *)jmalloc(t*sizeof(short),"state remap");
1054        int j=0;
1055        for (;j<t;j++)
1056          *(s_remap[i]+j)=stopped;    // if no remap found, then go to stopped state
1057      }
1058      else s_remap[i]=0;
1059
1060      int j=0;
1061      for (;j<t;j++)
1062      {
1063        fp->read(old_name,fp->read_byte());
1064        int new_type=o_remap[i];       
1065        if (new_type<total_objects)     // make sure old object still exsist
1066        {
1067          int k=0;
1068          for (;k<figures[new_type]->ts;k++)
1069          {
1070            if (figures[new_type]->seq[k] &&
1071               !strcmp(lstring_value(symbol_name(figures[new_type]->seq_syms[k])),old_name))
1072            *(s_remap[i]+j)=k;
1073          }
1074        }
1075      }
1076    }
1077
1078    short **v_remap=NULL;
1079    short *v_remap_totals=NULL;
1080    int load_vars=1;
1081    se=sd->find("describe_lvars");
1082    if (se)
1083    {
1084      v_remap=(short **)jmalloc(old_tot*sizeof(short *),"big var remap array");
1085      v_remap_totals=(short *)jmalloc(old_tot*sizeof(short),"big var rmp totals");
1086
1087      fp->seek(se->offset,0);
1088      int i=0;
1089      for (;i<old_tot;i++)
1090      {
1091        short t=fp->read_short();
1092        v_remap_totals[i]=t;
1093        if (t)
1094        {
1095          v_remap[i]=(short *)jmalloc(t*sizeof(short),"var remap");
1096          memset(v_remap[i],0xff,t*sizeof(short));
1097        } else { v_remap[i]=NULL; }
1098        int j=0;
1099        for (;j<t;j++)
1100        {
1101          fp->read(old_name,fp->read_byte());
1102          int new_type=o_remap[i];
1103          if (new_type!=0xffff)        // make sure old object still exsist
1104          {
1105            int k=0;
1106            for (;k<figures[new_type]->tiv;k++)
1107            {
1108              if (figures[new_type]->vars[k])
1109              {
1110                if (!strcmp(lstring_value(symbol_name(figures[new_type]->vars[k])),old_name))
1111                  *(v_remap[i]+j)=figures[new_type]->var_index[k];
1112              }
1113            }
1114          }
1115        }
1116      }
1117      load_vars=1;
1118    }
1119   
1120    se=sd->find("object_list");
1121    if (se)
1122    {
1123      total_objs=fp->read_long();   
1124
1125      se=sd->find("type");
1126      if (se)
1127      {
1128        fp->seek(se->offset,0);
1129        last=NULL;
1130        if (fp->read_byte()==RC_S)    //  read type array, this should be type RC_S
1131        {
1132          int i=0;
1133          for (;i<total_objs;i++)
1134          {
1135            ushort t=fp->read_short();
1136            game_object *p=new game_object(o_remap[t],1);
1137            clear_tmp();
1138            if (!first) first=p; else last->next=p;
1139            last=p; p->next=NULL;                 
1140          }
1141       
1142          se=sd->find("state");
1143          if (se)
1144          {
1145            fp->seek(se->offset,0);
1146            if (fp->read_byte()==RC_S)    //  read state array, this should be type RC_S
1147            {
1148              game_object *l=first;
1149              for (i=0;i<total_objs;i++,l=l->next)
1150              {
1151                int st=fp->read_short();
1152                if (l->otype==0xffff)
1153                  l->state=stopped;
1154                else
1155                {
1156                  character_state s=(character_state)(*(s_remap[o_backmap[l->otype]]+st));
1157                  if (l->has_sequence((character_state)s))
1158                    l->state=s;
1159                  else l->state=stopped;
1160                  l->current_frame=0;
1161                }
1162              }
1163            }
1164          }
1165       
1166          se=sd->find("lvars");
1167          if (se && load_vars)
1168          {
1169            fp->seek(se->offset,0);
1170            int abort=0;
1171            game_object *o=first;
1172            for (;o && !abort;o=o->next)
1173            {
1174              short ot=fp->read_short();
1175              int k=0;
1176              for (;k<ot;k++)
1177              {
1178                if (fp->read_byte()!=RC_L) abort=1;
1179                else
1180                {
1181                  long v=fp->read_long();
1182                  if (o->otype!=0xffff)     // non-exstant object
1183                  {
1184                    int remap=*(v_remap[o_backmap[o->otype]]+k);
1185                    if (remap!=-1 && figures[o->otype]->tiv>=k)
1186                    {
1187                      o->lvars[remap]=v;       
1188                    }
1189                  }
1190                }
1191              }
1192            }
1193          }
1194
1195          int frame_var=0;
1196          for (i=0;i<TOTAL_OBJECT_VARS;i++)
1197            if (!strcmp(object_descriptions[i].name,"cur_frame"))
1198              frame_var=i;
1199           
1200
1201          int j=0;
1202          for (;j<default_simple.total_vars();j++)
1203          {
1204            spec_entry *se=sd->find(object_descriptions[j].name);
1205            if (se)
1206            {
1207              fp->seek(se->offset,0);
1208              int t=object_descriptions[j].type;
1209              if (fp->read_byte()!=t)
1210                dprintf("Warning : load level -> var '%s' size changed\n");
1211              else
1212              {
1213                game_object *f=first;
1214                for (;f;f=f->next)
1215                {             
1216                  switch (t)
1217                  {
1218                    case RC_C :
1219                    { f->set_var(j,fp->read_byte()); } break;
1220                    case RC_S :
1221                    { f->set_var(j,fp->read_short()); } break;
1222                    case RC_L :
1223                    { f->set_var(j,fp->read_long()); } break;
1224                  }
1225                 
1226                  // check to make sure the frame number is not out of bounds from the time
1227                  // it was last saved
1228                  if (j==frame_var)
1229                  {
1230                    if (f->otype!=0xffff && f->current_frame>=
1231                        figures[f->otype]->get_sequence(f->state)->length())
1232                    f->current_frame=0;
1233                  }
1234                }
1235              }     
1236            } else dprintf("Warning : load level -> no previous var %s\n",default_simple.var_name(j));
1237          }
1238        }
1239      }
1240    }
1241   
1242    int k=0;
1243    for (;k<old_tot;k++)
1244    {
1245      if (s_remap_totals[k])
1246        jfree(s_remap[k]);
1247    }
1248
1249    int l=0;
1250    for (;l<old_tot;l++)
1251    {
1252      if (v_remap_totals[l])
1253        jfree(v_remap[l]);
1254    }
1255    jfree(v_remap_totals);
1256    jfree(s_remap_totals);
1257    jfree(o_remap);
1258    jfree(o_backmap);
1259    jfree(s_remap);
1260    jfree(v_remap);
1261  } 
1262 
1263}
1264
1265level::level(spec_directory *sd, bFILE *fp, char *lev_name)
1266{
1267  spec_entry *e;
1268  area_list=NULL;
1269
1270  attack_list=NULL;
1271  attack_list_size=attack_total=0;
1272
1273  target_list=NULL;
1274  target_list_size=target_total=0;
1275
1276  block_list=NULL;
1277  block_list_size=block_total=0;
1278
1279  all_block_list=NULL;
1280  all_block_list_size=all_block_total=0;
1281  first_name=NULL;
1282
1283  the_game->need_refresh();
1284
1285  char cmd[100];
1286  sprintf(cmd,symbol_str("loading"),lev_name);
1287  stack_stat stat(cmd);
1288  Name=strcpy((char *)jmalloc(strlen(lev_name)+1,"lev name"),lev_name);
1289
1290  e=sd->find("first name");
1291  if (e)
1292  {
1293    fp->seek(e->offset,0);
1294    int len=fp->read_byte();   // read the length of the string
1295    first_name=(char *)jmalloc(len,"level first name");
1296    fp->read(first_name,len);    // read the string
1297  } else
1298  {
1299    first_name=(char *)jmalloc(strlen(Name)+1,"level first name");   
1300    strcpy(first_name,Name);
1301  }
1302
1303  e=sd->find("fgmap");
1304  int no_fg=0,no_bg=0;
1305
1306  if (e)
1307  {   
1308    fp->seek(e->offset,0);
1309    fg_width=fp->read_long();
1310    fg_height=fp->read_long();
1311    map_fg=(unsigned short *)jmalloc(2*fg_width*fg_height,"Map fg : loaded");
1312    fp->read((char *)map_fg,2*fg_width*fg_height);
1313    int t=fg_width*fg_height;
1314    unsigned short *map=map_fg;
1315    while (t) { *map=lstl(*map); map++; t--; }
1316  } else
1317  {
1318    the_game->show_help("Warning foreground map missing");
1319    no_fg=1;
1320  }
1321  stat_man->update(5);
1322
1323  e=sd->find("bgmap");
1324  if (e)
1325  {
1326    fp->seek(e->offset,0);
1327    bg_width=fp->read_long();
1328    bg_height=fp->read_long();
1329    map_bg=(unsigned short *)jmalloc(2*bg_width*bg_height,"Map bg : loaded");
1330    fp->read((char *)map_bg,2*bg_width*bg_height);
1331    int t=bg_width*bg_height;
1332    unsigned short *map=map_bg;
1333    while (t) { *map=lstl(*map); map++; t--; }
1334  } else
1335  {
1336    the_game->show_help("Warning background map missing");
1337    no_bg=1;
1338  }
1339
1340  if (no_fg && !no_bg)
1341  {
1342    fg_width=bg_width;
1343    fg_height=bg_height;
1344    map_fg=(unsigned short *)jmalloc(2*fg_width*fg_height,"Map fg : loaded");
1345    memset(map_fg,0,2*fg_width*fg_height);
1346  }
1347
1348  if (no_bg)
1349  {
1350    bg_width=fg_width/8+8;
1351    bg_height=fg_height/8+8;
1352    map_bg=(unsigned short *)jmalloc(2*bg_width*bg_height,"Map bg : loaded");
1353    memset(map_bg,0,2*bg_width*bg_height);
1354  }
1355  stat_man->update(10);
1356
1357  /***************** Check map for non exsistant tiles **************************/
1358  long i,w;
1359  unsigned short *m; 
1360  spec_entry *load_all=sd->find("player_info");
1361  for (i=0,w=fg_width*fg_height,m=map_fg;i<w;i++,m++)
1362  {
1363    if (!load_all)
1364      (*m)=(*m)&(~0x8000);    // clear the has-seen bit on the tile
1365
1366    if (fgvalue(*m)>=nforetiles || foretiles[fgvalue(*m)]<0)
1367      *m=0; 
1368  }
1369
1370  for (i=0,w=bg_width*bg_height,m=map_bg;i<w;i++,m++)
1371  {
1372    if ( (bgvalue(*m)>=nbacktiles) || backtiles[bgvalue(*m)]<0)
1373       *m=0; 
1374  }
1375
1376  load_options(sd,fp);
1377  stat_man->update(15);
1378
1379//  first=first_active=last=NULL;
1380  load_objects(sd,fp);
1381  stat_man->update(25);
1382
1383  object_node *players,*objs;
1384  players=make_player_onodes();
1385  objs=make_not_list(players);
1386
1387
1388
1389  read_lights(sd,fp,lev_name);
1390  load_links(fp,sd,objs,players);
1391  int players_got_loaded=load_player_info(fp,sd,objs);
1392
1393
1394  game_object *l=first;
1395  for (;l;)
1396  {
1397    game_object *p=l;
1398    l=l->next;
1399    if (p->otype==0xffff || p->x<0 || p->y<0)
1400      delete_object(p);
1401  }
1402
1403  load_cache_info(sd,fp);
1404
1405  if (!players_got_loaded)
1406  {
1407    level *old=current_level;
1408    current_level=this;
1409   
1410    object_node *list=NULL;
1411    list=make_not_list(list);     // create a list of the object list in case objects change positions
1412
1413    object_node *ln=list;
1414    for (;ln;ln=ln->next)
1415      ln->me->reload_notify();
1416    delete_object_list(list);
1417
1418    current_level=old;
1419
1420    insert_players();
1421  }
1422
1423  delete_object_list(players);
1424  delete_object_list(objs);
1425
1426}
1427
1428
1429/*
1430   [object_descriptions] 2 total_type
1431   for(1..total_types)
1432   {
1433     ["object_names"]  1,(name)
1434
1435     ["object_states"]  2(total),<2=number,1,name>
1436
1437     ["object_lvars"]   2(total),<1(type),1,name>   
1438   }
1439
1440  [object_list]
1441   4 total_objects   
1442   for(1..total_objects)
1443   {
1444     ["type"]
1445     ["state"]
1446     ["lvars"]
1447     ...
1448   }
1449
1450*/
1451
1452
1453void get_prof_assoc_filename(char *filename, char *prof_filename)
1454{
1455  char *s1,*s2,*dot=NULL;
1456  for (s1=filename,s2=prof_filename,dot=NULL;*s1;s1++,s2++)
1457  {
1458    *s2=*s1;
1459    if (*s1=='.') dot=s2;   
1460  }
1461  if (dot) s2=dot+1;
1462
1463  *(s2++)='c';
1464  *(s2++)='p';
1465  *(s2++)='f';
1466  *s2=0;
1467}
1468
1469void level::level_loaded_notify()
1470{
1471  char *n;
1472  if (first_name)
1473    n=first_name;
1474  else
1475    n=name();
1476  if (strstr(n,"levels/level"))
1477  {
1478    char nm[100];
1479    sprintf(nm,"music/abuse%c%c.hmi",n[12],n[13]);
1480    bFILE *fp=open_file(nm,"rb");
1481    if (fp->open_failure())
1482    {
1483      delete fp;
1484    }
1485    else
1486    {
1487      if (current_song) { current_song->stop(); delete current_song; }
1488
1489      delete fp;
1490      current_song=new song(nm);
1491      current_song->play(music_volume);
1492    }
1493  }
1494 
1495/*  if (DEFINEDP(symbol_function(l_level_loaded)))
1496  {
1497    int sp=current_space;
1498    current_space=PERM_SPACE;
1499
1500    void *arg_list=NULL;
1501    p_ref r1(arg_list);
1502    push_onto_list(new_lisp_string(n),arg_list);
1503    eval_function((lisp_symbol *)l_level_loaded,arg_list);
1504
1505    current_space=sp;
1506  } */
1507}
1508
1509
1510bFILE *level::create_dir(char *filename, int save_all,
1511                         object_node *save_list, object_node *exclude_list)
1512{
1513  spec_directory sd;
1514  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"Copyright 1995 Crack dot Com, All Rights reserved",NULL,0,0));
1515  if (first_name)
1516    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"first name",NULL,strlen(first_name)+2,0));
1517   
1518
1519
1520  sd.add_by_hand(new spec_entry(SPEC_GRUE_FGMAP,"fgmap",NULL,4+4+fg_width*fg_height*2,0));
1521  sd.add_by_hand(new spec_entry(SPEC_GRUE_BGMAP,"bgmap",NULL,4+4+bg_width*bg_height*2,0));
1522  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"bg_scroll_rate",NULL,1+4*4,0));
1523
1524  int ta=0;
1525  area_controller *a=area_list;
1526  for (;a;a=a->next) ta++;
1527
1528  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"area_list.v1",NULL,1+ta*(4*11)+4,0));
1529 
1530  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"tick_counter",NULL,1+4,0));
1531
1532
1533
1534  // how many object types are we goint to save, use a short to specify how many
1535  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"object_descripitions",NULL,2,0));
1536
1537
1538  int size=0;
1539  int i=0;
1540  for (;i<total_objects;i++)       // now save the names of the objects so if ordering
1541    size+=1+strlen(object_names[i])+1;    // changes in future versions we can adjust in load
1542  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"describe_names",NULL,size,0));
1543
1544
1545  size=0;                               
1546  for (i=0;i<total_objects;i++)
1547  {
1548    size+=2;  // total number of states
1549    int j=0;
1550    for (;j<figures[i]->ts;j++)
1551      if (figures[i]->seq[j])
1552        size+=1+strlen(lstring_value(symbol_name(figures[i]->seq_syms[j])))+1;
1553  }
1554  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"describe_states",NULL,size,0));
1555
1556
1557
1558  size=0;
1559  for (i=0;i<total_objects;i++)
1560  {
1561    size+=2;  // total number of variables
1562    int j=0;
1563    for (;j<figures[i]->tiv;j++)
1564      if (figures[i]->vars[j])
1565        size+=1+strlen(lstring_value(symbol_name(figures[i]->vars[j])))+1;
1566  }
1567  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"describe_lvars",NULL,size,0));
1568
1569 
1570
1571  // how many objects are we goint to save, use a long to specify how many
1572  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"object_list",NULL,4,0));
1573 
1574  long t=0;
1575  object_node *o=save_list;
1576  for (;o;o=o->next)
1577    t++;
1578
1579  // type and state aren't normal records because they will be remapped on loading
1580  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"type",NULL,1+2*t,0));
1581  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"state",NULL,1+2*t,0));
1582
1583
1584  // now save all the lvars for each object
1585  for (size=0,o=save_list;o;o=o->next)
1586    size+=figures[o->me->otype]->tv*5+2;
1587  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"lvars",NULL,size,0));
1588
1589
1590  for (i=0;i<TOTAL_OBJECT_VARS;i++)
1591    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,object_descriptions[i].name,NULL,1+
1592                          RC_type_size(object_descriptions[i].type)*t,0));
1593
1594  add_light_spec(&sd,Name);
1595
1596
1597  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"object_links",NULL,1+4+total_object_links(save_list)*8,0));
1598  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"light_links",NULL,1+4+total_light_links(save_list)*8,0));
1599
1600  if (save_all)
1601  {
1602    t=0;
1603    view *v=player_list;
1604    for (;v;v=v->next) t++;
1605    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"player_info",NULL,t*4+4,0));
1606
1607    int tv=total_view_vars();
1608    int i=0;
1609    for (;i<tv;i++)
1610      sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,get_view_var_name(i),NULL,1+4*t,0));
1611    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"random_start",NULL,5,0));
1612
1613    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"weapon_array",NULL,1+4+total_weapons*4*t,0));
1614
1615    int name_len=0;
1616    for (v=player_list;v;v=v->next)
1617      name_len+=strlen(v->name)+2;
1618    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"player_names",NULL,name_len,0));
1619
1620    sd.add_by_hand(new spec_entry(SPEC_IMAGE,"thumb nail",NULL,4+160*(100+eh->font()->height()*2),0));
1621  }
1622
1623  sd.calc_offsets();
1624
1625  return sd.write(filename);
1626}
1627
1628void scale_put(image *im, image *screen, int x, int y, short new_width, short new_height);
1629
1630void level::write_thumb_nail(bFILE *fp, image *im)
1631{
1632  image *i=new image(160,100+eh->font()->height()*2);
1633  i->clear();
1634  scale_put(im,i,0,0,160,100);
1635  if (first_name)
1636    eh->font()->put_string(i,80-strlen(first_name)*eh->font()->width()/2,100,first_name);
1637
1638  time_t t;
1639  t=time(NULL);
1640  char buf[80];
1641
1642  strftime(buf,80,"%T %A %B %d",localtime(&t)); 
1643  eh->font()->put_string(i,80-strlen(buf)*eh->font()->width()/2,100+eh->font()->height(),buf);
1644
1645  fp->write_short(i->width());
1646  fp->write_short(i->height());
1647  int y=0;
1648  for (;y<i->height();y++)
1649    fp->write(i->scan_line(y),i->width());
1650
1651  delete i;
1652}
1653
1654void level::write_player_info(bFILE *fp, object_node *save_list)
1655{
1656  long t=0;
1657  view *v=player_list;
1658  for (;v;v=v->next) t++;
1659  fp->write_long(t);
1660
1661  for (v=player_list;v;v=v->next)
1662    fp->write_long(object_to_number_in_list(v->focus,save_list));
1663
1664  int tv=total_view_vars();
1665  int i=0;
1666  for (;i<tv;i++)
1667  {
1668    fp->write_byte(RC_L);
1669    for (v=player_list;v;v=v->next)
1670      fp->write_long(v->get_view_var_value(i));
1671  }
1672
1673  fp->write_byte(RC_L);
1674  fp->write_long(rand_on);
1675
1676  fp->write_byte(RC_L);
1677  fp->write_long(total_weapons);
1678  for (v=player_list;v;v=v->next)
1679    for (i=0;i<total_weapons;i++)
1680      fp->write_long(v->weapons[i]);
1681
1682  for (v=player_list;v;v=v->next)
1683  {
1684    int len=strlen(v->name)+1;
1685    fp->write_byte(len);
1686    fp->write(v->name,len);
1687  }
1688}
1689
1690
1691int level::load_player_info(bFILE *fp, spec_directory *sd, object_node *save_list)
1692{
1693  int ret;
1694  spec_entry *se=sd->find("player_info");
1695  if (se)
1696  {
1697    fp->seek(se->offset,0);
1698
1699    int set_first_view=0;
1700    if (the_game->first_view==player_list) set_first_view=1;
1701    int my_player_number=-1;
1702
1703    view *v=player_list;
1704    for (;v;v=v->next)
1705    { v->suggest.send_view=0;
1706      v->suggest.send_weapon_change=0;
1707    }
1708
1709    for (v=player_list;v;v=v->next)
1710      if (v->local_player())
1711         my_player_number=v->player_number;
1712
1713    while (player_list)    // delete all of the views (they will get recreated)
1714    {
1715      v=player_list;
1716      if (v->focus)
1717      {
1718        if (v->focus->controller())
1719         v->focus->set_controller(NULL);
1720        delete v->focus;
1721      }
1722
1723      player_list=player_list->next;
1724      delete v;
1725    }
1726
1727    long total_players=fp->read_long();
1728    view *last=NULL;
1729    int i=0;
1730    for (;i<total_players;i++)   
1731    {
1732      game_object *o=number_to_object_in_list(fp->read_long(),save_list);
1733      v=new view(o,NULL,0);
1734      if (o) o->set_controller(v);
1735      if (player_list)
1736        last->next=v;
1737      else player_list=v;
1738      last=v;
1739    }
1740    if (set_first_view)
1741      the_game->first_view=player_list;
1742   
1743    for (i=0;i<total_view_vars();i++)
1744    {
1745      char *find_name=get_view_var_name(i);
1746      se=sd->find(find_name);
1747
1748      if (se)
1749      {
1750        fp->seek(se->offset,0);
1751        if (fp->read_byte()==RC_L)
1752        {
1753          for (v=player_list;v;v=v->next)
1754            v->set_view_var_value(i,fp->read_long());
1755        }
1756      } else
1757      {
1758        for (v=player_list;v;v=v->next)
1759          v->set_view_var_value(i,0);
1760      }
1761    }
1762
1763    se=sd->find("random_start");      // start of index into random table
1764    if (se)
1765    {
1766      fp->seek(se->offset,0);
1767      if (fp->read_byte()==RC_L)
1768        rand_on=fp->read_long();
1769    } else rand_on=0;
1770
1771    se=sd->find("weapon_array");
1772    if (se)
1773    {
1774      fp->seek(se->offset,0);
1775      if (fp->read_byte()==RC_L)
1776      {
1777        long m=fp->read_long();  // read how many weapons exsisted when last saved
1778        int i;
1779        for (v=player_list;v;v=v->next)   
1780        {
1781          for (i=0;i<m;i++)
1782          {
1783            long x=fp->read_long();
1784            if (i<total_weapons)
1785            {
1786              v->weapons[i]=x;
1787              v->last_weapons[i]=x;
1788            }
1789          }
1790        }
1791      }
1792    }  else
1793    {
1794      for (v=player_list;v;v=v->next)     
1795      {
1796        memset(v->last_weapons,0xff,total_weapons*sizeof(long));
1797        memset(v->weapons,0xff,total_weapons*sizeof(long));
1798      }
1799    }
1800
1801    se=sd->find("player_names");
1802    if (se)
1803    {
1804      fp->seek(se->offset,0);
1805      for (v=player_list;v;v=v->next)     
1806      {
1807        uchar len=fp->read_byte();
1808        fp->read(v->name,len);
1809      }
1810    }
1811
1812    ret=1;
1813    recalc_local_view_space();
1814   
1815  } else
1816  {
1817    void *fun=make_find_symbol("set_player_defaults");
1818    if (DEFINEDP(symbol_function(fun)))
1819    {     
1820      view *f;
1821      game_object *o=current_object;
1822      for (f=player_list;f;f=f->next)
1823      {
1824        if (f->focus)
1825        {
1826          current_object=f->focus;
1827          void *m=mark_heap(TMP_SPACE);
1828          eval_function((lisp_symbol *)fun,NULL);
1829          restore_heap(m,TMP_SPACE);
1830        }
1831      }
1832      current_object=o;
1833    }
1834    ret=0;
1835  }
1836
1837  view *vw;
1838  for (vw=player_list;vw;vw=vw->next)
1839  {
1840    if (total_weapons && !vw->has_weapon(vw->current_weapon))
1841    {
1842      vw->suggest.send_weapon_change=1;
1843      vw->suggest.new_weapon=0;     
1844    }
1845  }
1846
1847  return ret;
1848}
1849
1850
1851void level::write_objects(bFILE *fp, object_node *save_list)
1852{
1853  // record information in the file about what the data structures look like
1854  // right now, so if they change later, they don't get get screwed up
1855  fp->write_short(total_objects);   // mark how many objects we know about right now 
1856
1857  int i=0;
1858  for (;i<total_objects;i++)   // loop through all the object types we know of
1859  {   
1860    fp->write_byte(strlen(object_names[i])+1);                    // sizeof name   
1861    fp->write(object_names[i],strlen(object_names[i])+1);      // write object name
1862  }
1863   
1864
1865  // write state numbers and names for each object
1866  for (i=0;i<total_objects;i++)
1867  {
1868    int total=0;
1869    int j=0;
1870    for (;j<figures[i]->ts;j++)
1871      if (figures[i]->seq[j]) total++;
1872    fp->write_short(total);
1873
1874    for (j=0;j<figures[i]->ts;j++)
1875      if (figures[i]->seq[j])
1876      {
1877        char *state_name=lstring_value(symbol_name(figures[i]->seq_syms[j]));
1878        fp->write_byte(strlen(state_name)+1);
1879        fp->write(state_name,strlen(state_name)+1);
1880      }
1881  }
1882
1883 
1884  // write object lvar names
1885  for (i=0;i<total_objects;i++)
1886  {
1887    fp->write_short(figures[i]->tv);
1888    int j,x;
1889   
1890    for (x=0;x<figures[i]->tv;x++)
1891    {
1892      for (j=0;j<figures[i]->tiv;j++)
1893      {
1894        if (figures[i]->vars[j] && figures[i]->var_index[j]==x)
1895        {
1896          char *var_name=lstring_value(symbol_name(figures[i]->vars[j]));
1897          fp->write_byte(strlen(var_name)+1);
1898          fp->write(var_name,strlen(var_name)+1);
1899        }
1900      }
1901    }
1902  }
1903 
1904  long t=0;
1905  object_node *o=save_list;
1906  for (;o;o=o->next) t++;
1907  fp->write_long(t);
1908
1909
1910  fp->write_byte(RC_S);                                    // save type info for each record
1911  for (o=save_list;o;o=o->next) fp->write_short(o->me->type());   
1912
1913  fp->write_byte(RC_S);                                    // save state info for each record
1914  for (o=save_list;o;o=o->next) fp->write_short(o->me->reduced_state());
1915
1916  for (o=save_list;o;o=o->next)                            // save lvars
1917  {
1918    fp->write_short(figures[o->me->otype]->tv);
1919    for (i=0;i<figures[o->me->otype]->tv;i++)
1920    {
1921      fp->write_byte(RC_L);                           // for now the only type allowed is long
1922      fp->write_long(o->me->lvars[i]);
1923    }
1924  }
1925
1926  for (i=0;i<default_simple.total_vars();i++)
1927  {
1928    int t=object_descriptions[i].type;
1929    fp->write_byte(t);
1930    for (o=save_list;o;o=o->next)
1931    {
1932      switch (t)
1933      {         
1934        case RC_C :
1935        { fp->write_byte(o->me->get_var(i)); } break;
1936        case RC_S :
1937        { fp->write_short(o->me->get_var(i)); } break;
1938        case RC_L :
1939        { fp->write_long(o->me->get_var(i)); } break;
1940      }
1941    }
1942  }
1943}
1944
1945
1946long level::total_object_links(object_node *list)
1947{
1948  long tl=0;
1949  for (object_node *o=list;o;o=o->next)
1950    tl+=o->me->total_objects();
1951  return tl;
1952}
1953
1954long level::total_light_links(object_node *list)
1955{
1956  long tl=0;
1957  for (object_node *o=list;o;o=o->next)
1958    tl+=o->me->total_lights();
1959  return tl;
1960}
1961
1962void level::write_links(bFILE *fp, object_node *save_list, object_node *exclude_list)
1963{
1964  fp->write_byte(RC_L); 
1965  fp->write_long(total_object_links(save_list));
1966
1967  int x=1;
1968  object_node *o=save_list;
1969
1970  for (;o;o=o->next,x++)
1971  {
1972    int i=0;
1973    for (;i<o->me->total_objects();i++)
1974    {
1975      fp->write_long(x);
1976      long x=object_to_number_in_list(o->me->get_object(i),save_list);
1977      if (x)
1978        fp->write_long(x);
1979      else                            // save links to excluded items as negative
1980        fp->write_long((long)(-(object_to_number_in_list(o->me,exclude_list))));
1981    }
1982  }
1983
1984  fp->write_byte(RC_L); 
1985  fp->write_long(total_light_links(save_list));
1986
1987  x=1;
1988  for (o=save_list;o;o=o->next,x++)
1989  {
1990    int i=0;
1991    for (;i<o->me->total_lights();i++)
1992    {
1993      fp->write_long(x);
1994      fp->write_long(light_to_number(o->me->get_light(i)));
1995    }
1996  }
1997
1998}
1999
2000
2001void level::load_links(bFILE *fp, spec_directory *sd,
2002                       object_node *save_list, object_node *exclude_list)
2003{
2004  spec_entry *se=sd->find("object_links");
2005  if (se)
2006  {
2007    fp->seek(se->offset,0);
2008    if (fp->read_byte()==RC_L)
2009    {
2010      long t=fp->read_long();
2011      while (t)
2012      {
2013        long x1=fp->read_long();
2014        CONDITION(x1>=0,"expected x1 for object link to be > 0\n");
2015        long x2=fp->read_long();
2016        game_object *p,*q=number_to_object_in_list(x1,save_list);
2017        if (x2>0)
2018          p=number_to_object_in_list(x2,save_list);
2019        else p=number_to_object_in_list(-x2,exclude_list);
2020        if (q)
2021          q->add_object(p);
2022        else dprintf("bad object link\n");
2023
2024        t--;
2025      }
2026    }
2027  }
2028
2029  se=sd->find("light_links");
2030  if (se)
2031  {
2032    fp->seek(se->offset,0);
2033    if (fp->read_byte()==RC_L)
2034    {
2035      long t=fp->read_long();
2036      while (t)
2037      {
2038        long x1=fp->read_long();
2039        long x2=fp->read_long();
2040        game_object *p=number_to_object_in_list(x1,save_list);
2041        if (p)
2042          p->add_light(number_to_light(x2));
2043        else dprintf("bad object/light link\n");
2044        t--;
2045      }
2046    }
2047  }
2048
2049}
2050
2051
2052void level::write_options(bFILE *fp)
2053{
2054  // save background scroll rate
2055  fp->write_byte(RC_L);
2056  fp->write_long(bg_xmul);
2057  fp->write_long(bg_xdiv);
2058  fp->write_long(bg_ymul);
2059  fp->write_long(bg_ydiv);
2060
2061  fp->write_byte(RC_L);
2062  int ta=0;
2063  area_controller *a=area_list;
2064  for (;a;a=a->next) ta++;
2065  fp->write_long(ta);
2066  for (a=area_list;a;a=a->next)
2067  {
2068    fp->write_long(a->x);
2069    fp->write_long(a->y);
2070    fp->write_long(a->w);
2071    fp->write_long(a->h);
2072    fp->write_long(a->active);
2073
2074    fp->write_long(a->ambient);
2075    fp->write_long(a->view_xoff);
2076    fp->write_long(a->view_yoff);
2077    fp->write_long(a->ambient_speed);
2078    fp->write_long(a->view_xoff_speed);
2079    fp->write_long(a->view_yoff_speed);
2080  }
2081  fp->write_byte(RC_L);
2082  fp->write_long(tick_counter());
2083}
2084
2085void level::load_options(spec_directory *sd, bFILE *fp)
2086{
2087  spec_entry *se=sd->find("bg_scroll_rate");
2088  if (se)
2089  {
2090    fp->seek(se->offset,0);
2091    if (fp->read_byte()!=RC_L)
2092    { bg_xmul=bg_ymul=1; bg_xdiv=bg_ydiv=8; }
2093    else
2094    {
2095      bg_xmul=fp->read_long();
2096      bg_xdiv=fp->read_long();
2097      bg_ymul=fp->read_long();
2098      bg_ydiv=fp->read_long();
2099    }
2100  } else { bg_xmul=bg_ymul=1; bg_xdiv=bg_ydiv=8; }
2101
2102  se=sd->find("area_list.v1");
2103  if (se)
2104  {
2105    fp->seek(se->offset,0);
2106    if (fp->read_byte()==RC_L)
2107    {
2108      area_controller *l=NULL,*p;
2109      long ta=fp->read_long();
2110      int i=0;
2111      for (;i<ta;i++)
2112      {
2113        long x,y,w,h;
2114        x=fp->read_long();
2115        y=fp->read_long();
2116        w=fp->read_long();
2117        h=fp->read_long();     
2118        p=new area_controller(x,y,w,h,NULL);
2119        if (l) l->next=p;
2120        else area_list=p;
2121        l=p;
2122        p->active=fp->read_long();
2123        p->ambient=fp->read_long();
2124        p->view_xoff=fp->read_long();
2125        p->view_yoff=fp->read_long();
2126        p->ambient_speed=fp->read_long();
2127        p->view_xoff_speed=fp->read_long();
2128        p->view_yoff_speed=fp->read_long();
2129      }
2130    }
2131  }
2132
2133  se=sd->find("tick_counter");
2134  if (se)
2135  {
2136    fp->seek(se->offset,0);
2137    if (fp->read_byte()==RC_L)   
2138      set_tick_counter(fp->read_long());
2139    else set_tick_counter(0);
2140  } else set_tick_counter(0);
2141}
2142
2143
2144void level::write_cache_prof_info()
2145{
2146  if (cash.prof_is_on())
2147  {
2148    char pf_name[100];
2149    if (first_name)
2150      get_prof_assoc_filename(first_name,pf_name);
2151    else
2152      get_prof_assoc_filename(Name,pf_name);
2153
2154
2155    spec_directory sd;
2156    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"cache profile info",NULL,cash.prof_size(),0));
2157    sd.calc_offsets();
2158    jFILE *fp2=sd.write(pf_name);
2159    if (!fp2)
2160      the_game->show_help("Unable to open cache profile output file");
2161    else
2162    {
2163      cash.prof_write(fp2);
2164      delete fp2;
2165    }
2166    sd.delete_entries();
2167  }
2168
2169}
2170
2171void level::load_cache_info(spec_directory *sd, bFILE *fp)
2172{
2173  if (!DEFINEDP(symbol_value(l_empty_cache)) || !symbol_value(l_empty_cache))
2174  {
2175    char pf_name[100];
2176    if (first_name)
2177      get_prof_assoc_filename(first_name,pf_name);  // get cache info from orignal filename if this is a savegame
2178    else
2179      get_prof_assoc_filename(Name,pf_name);
2180
2181
2182    cash.load_cache_prof_info(pf_name,this);
2183  }
2184}
2185
2186
2187int level::save(char *filename, int save_all)
2188{
2189        char name[255], bkname[255];
2190
2191        sprintf( name, "%s%s", get_save_filename_prefix(), filename );
2192        sprintf( bkname, "%slevsave.bak", get_save_filename_prefix() );
2193        if( !save_all && DEFINEDP( symbol_value( l_keep_backup ) ) &&
2194                symbol_value( l_keep_backup ) )   // make a backup
2195        {
2196                bFILE *fp = open_file( name, "rb" );    // does file already exist?
2197                if( !fp->open_failure() )
2198                {
2199                        unlink( bkname );
2200                        bFILE *bk = open_file( bkname, "wb" );
2201                        if( bk->open_failure() )
2202                                dprintf("unable to open backup file %s\n", bkname );
2203                        else
2204                        {
2205                                long size = fp->file_size();
2206                                uchar *buf = (uchar *)jmalloc(0x1000,"copy buf");
2207                                int tr = 1;
2208                                while( size && tr )
2209                                {
2210                                        int tr = fp->read(buf,0x1000);
2211                                        if( tr )
2212                                        tr = bk->write(buf,tr);
2213                                        size -= tr;
2214                                }
2215                                jfree(buf);
2216                        }
2217                        delete bk;
2218#if (defined(__MACH__) || !defined(__APPLE__))
2219                        chmod( bkname, S_IRWXU | S_IRWXG | S_IRWXO );
2220#endif
2221                }
2222                delete fp;
2223        }
2224
2225        // if we are not doing a savegame then change the first_name to this name
2226        if( !save_all )
2227        {
2228                if( first_name )
2229                        jfree(first_name);
2230                first_name = (char *)jmalloc( strlen( name ) + 1, "level first name" );
2231                strcpy( first_name, name );
2232        }
2233
2234        object_node *players, *objs;
2235        if( save_all )
2236                players = NULL;
2237        else
2238                players = make_player_onodes();
2239
2240        objs = make_not_list(players);     // negate the above list
2241
2242        bFILE *fp = create_dir( name, save_all, objs, players);
2243        if( fp != NULL )
2244        {
2245                if( !fp->open_failure() )
2246                {
2247                        if( first_name )
2248                        {
2249                                fp->write_byte( strlen( first_name ) + 1 );
2250                                fp->write( first_name, strlen( first_name ) + 1 );
2251                        }
2252                        else
2253                        {
2254                                fp->write_byte( 1 );
2255                                fp->write_byte( 0 );
2256                        }
2257
2258                        fp->write_long( fg_width );
2259                        fp->write_long( fg_height );
2260
2261                        int t  = fg_width * fg_height;
2262                        ushort *rm = map_fg;
2263                        for (;t;t--,rm++)
2264                        {
2265                                ushort x = *rm;
2266                                x = lstl(x);            // convert to intel endianess
2267                                *rm = x;
2268                        }
2269
2270                        fp->write( (char *)map_fg, 2 * fg_width * fg_height );
2271                        t = fg_width * fg_height;
2272                        rm = map_fg;
2273                        for (;t;t--,rm++)
2274                        {
2275                                ushort x = *rm;
2276                                x = lstl( x );            // convert to intel endianess
2277                                *rm = x;
2278                        }
2279
2280                        fp->write_long( bg_width );
2281                        fp->write_long( bg_height );
2282                        t = bg_width * bg_height;
2283                        rm = map_bg;
2284
2285                        for (;t;t--,rm++)
2286                        {
2287                                ushort x=*rm;
2288                                x = lstl( x );          // convert to intel endianess
2289                                *rm = x;
2290                        }
2291
2292                        fp->write( (char *)map_bg, 2 * bg_width * bg_height );
2293                        rm = map_bg;
2294                        t = bg_width*bg_height;
2295
2296                        for (;t;t--,rm++)
2297                        {
2298                                ushort x = *rm;
2299                                x = lstl( x );          // convert to intel endianess
2300                                *rm = x;
2301                        }
2302
2303                        write_options( fp );
2304                        write_objects( fp, objs );
2305                        write_lights( fp );
2306                        write_links( fp, objs, players );
2307                        if( save_all )
2308                        {
2309                                write_player_info( fp, objs );
2310                                write_thumb_nail( fp,screen );
2311                        }
2312
2313                        delete fp;
2314#if (defined(__MACH__) || !defined(__APPLE__))
2315                        chmod( name, S_IRWXU | S_IRWXG | S_IRWXO );
2316#endif
2317                        write_cache_prof_info();
2318                }
2319                else
2320                {
2321                        the_game->show_help( "Unable to open file for saving\n" );
2322                        delete fp;
2323                        return 0;
2324                }
2325        }
2326        else
2327        {
2328                the_game->show_help( "Unable to open file for saving.\n" );
2329                printf( "\nFailed to save game.\n" );
2330                printf( "I was trying to save to: '%s'\n\tPath: '%s'\n\tFile: '%s'\n", name, get_save_filename_prefix(), filename );
2331                printf( "\nPlease send an email to:\n\ttrandor@labyrinth.net.au\nwith these details.\nThanks.\n" );
2332                return 0;
2333        }
2334
2335        delete_object_list(players);
2336        delete_object_list(objs);
2337
2338        return 1;
2339}
2340
2341level::level(int width, int height, char *name)
2342{
2343  the_game->need_refresh();
2344  area_list=NULL;
2345  set_tick_counter(0);
2346
2347  attack_list=NULL;
2348  attack_list_size=attack_total=0;
2349
2350  target_list=NULL;
2351  target_list_size=target_total=0;
2352
2353  block_list=NULL;
2354  block_list_size=block_total=0;
2355
2356  all_block_list=NULL;
2357  all_block_list_size=all_block_total=0;
2358 
2359  Name=NULL;
2360  first_name=NULL;
2361
2362  set_name(name);
2363  first=first_active=NULL;
2364 
2365  fg_width=width;
2366  fg_height=height;
2367  calc_bgsize(fg_width,fg_height,bg_width,bg_height);
2368 
2369  map_bg=(unsigned short *)jmalloc(sizeof(short)*bg_width*bg_height,"map bg");
2370  map_fg=(unsigned short *)jmalloc(sizeof(short)*fg_width*fg_height,"map fg");
2371
2372
2373
2374  memset(map_bg,0,sizeof(short)*bg_width*bg_height);
2375  memset(map_fg,0,sizeof(short)*fg_width*fg_height);
2376
2377  int i; 
2378  for (i=0;i<fg_width;i++)
2379  {   
2380    map_fg[i]=1;
2381    map_fg[fg_width*(fg_height-1)+i]=1;
2382  }
2383  for (i=0;i<fg_height;i++)
2384  {   
2385    map_fg[fg_width*i]=1;
2386    map_fg[fg_width*i+fg_width-1]=1;
2387  }
2388 
2389  total_objs=0; 
2390  insert_players();
2391}
2392
2393
2394void level::add_object(game_object *new_guy)
2395{
2396  total_objs++;
2397  new_guy->next=NULL;
2398  if (figures[new_guy->otype]->get_cflag(CFLAG_ADD_FRONT))
2399  {
2400    if (!first)
2401      first=new_guy;
2402    else
2403      last->next=new_guy;
2404    last=new_guy;
2405  } else
2406  {
2407    if (!first)
2408      last=first=new_guy;
2409    else
2410    {
2411      new_guy->next=first;
2412      first=new_guy;
2413    }
2414  }
2415}
2416
2417void level::add_object_after(game_object *new_guy,game_object *who)
2418{
2419  if (!who) add_object(new_guy);
2420  else
2421  {
2422    total_objs++;
2423    if (who==last) last=new_guy;
2424    new_guy->next=who->next;
2425    who->next=new_guy;
2426  }
2427}
2428
2429void level::delete_object(game_object *who)
2430{
2431  remove_object(who);
2432  delete who;
2433}
2434
2435void level::remove_block(game_object *who)
2436{
2437  int i=0,j;
2438  game_object **o=block_list;
2439  for (;i<block_total;i++)
2440  {
2441    if (*o==who)        // is this object in the block list?
2442    {
2443      block_total--;    // squish the block list in
2444      o++;
2445      for (j=i;j<block_total;j++)
2446        block_list[j]=block_list[j+1];
2447    } else o++;   
2448  }
2449}
2450
2451
2452// searches through the all_block list for who and if it finds it deletes it
2453void level::remove_all_block(game_object *who)
2454{
2455  int i=0,j;
2456  game_object **o=all_block_list;
2457  for (;i<all_block_total;i++)
2458  {
2459    if (*o==who)        // is this object in the block list?
2460    {
2461      all_block_total--;    // squish the block list in
2462      o++;
2463      for (j=i;j<all_block_total;j++)
2464        all_block_list[j]=all_block_list[j+1];
2465    } else o++;   
2466  }
2467}
2468
2469void level::remove_object(game_object *who)
2470{
2471  if (dev_cont)
2472    dev_cont->notify_deleted_object(who);
2473
2474  if (who==first)
2475  {
2476    if (who==last) last=NULL;
2477    first=first->next;
2478  }
2479  else
2480  {
2481    game_object *o=first;
2482    for (;o && o->next!=who;o=o->next);
2483    if (o)
2484    {
2485      o->next=who->next;
2486      if (!o->next) last=o;
2487    }
2488    else return ;     // if object is not in level, don't try to do anything else
2489  }
2490  total_objs--;
2491
2492
2493  if (first_active==who)
2494    first_active=who->next_active;
2495  else
2496  {
2497    game_object *o=first_active;
2498    for (;o && o->next_active!=who;o=o->next_active);
2499    if (o)
2500      o->next_active=who->next_active;
2501  }
2502
2503  if (who->flags()&KNOWN_FLAG)
2504  {
2505    game_object *o=first;
2506    for (;o;o=o->next)
2507    {
2508      int t=o->total_objects();
2509      int i=0;
2510      for (;i<t;i++)
2511        if (o->get_object(i)==who)
2512        {
2513          o->remove_object(who);
2514          t=o->total_objects();
2515        }
2516    }
2517  }
2518
2519  if (who->otype<0xffff)
2520  {
2521    if (who->can_block())  // remove object from block list and all_block if nessasary
2522    {
2523      remove_block(who);
2524      remove_all_block(who);
2525    } else if (who->hurtable())
2526      remove_all_block(who);
2527  }
2528
2529
2530  int t=who->total_objects();
2531  while (t) { who->remove_object(who->get_object(0)); t--; }
2532
2533  t=who->total_lights();
2534  while (t) { who->remove_light(who->get_light(0)); t--; }
2535}
2536
2537void level::to_front(game_object *o)  // move to end of list, so we are drawn last, therefore top
2538{
2539  if (o==last) return ;
2540  first_active=NULL;     // make sure nothing goes screwy with the active list
2541
2542  if (o==first) 
2543    first=first->next; 
2544  else
2545  {
2546    game_object *w=first;
2547    for (;w && w->next!=o;w=w->next);
2548    if (!w) return ;
2549    w->next=o->next;
2550  }
2551
2552  last->next=o;
2553  o->next=NULL;
2554  last=o;
2555}
2556
2557void level::to_back(game_object *o)   // to make the character drawn in back, put at front of list
2558
2559  if (o==first) return;
2560  first_active=NULL;     // make sure nothing goes screwy with the active list 
2561 
2562  game_object *w=first;
2563  for (;w && w->next!=o;w=w->next);
2564  if (!w) return;
2565  if (last==o)
2566    last=w;
2567  w->next=o->next;
2568  o->next=first;
2569  first=o;
2570}
2571
2572
2573game_object *level::find_self(game_object *me)
2574{
2575  return me;
2576}
2577
2578game_object *level::find_object(long x, long y)
2579{
2580  long x1,y1,x2,y2; 
2581  game_object *o=first;
2582  for (;o;o=o->next)
2583  {
2584    o->picture_space(x1,y1,x2,y2);   
2585    if (x<x2 && x>=x1 && y<y2 && y>=y1)
2586      return o;
2587  }
2588  return NULL;
2589}
2590
2591long last_tile_hit_x,last_tile_hit_y;
2592
2593#define remapx(x) (x==0 ? -1 : x==tl-1 ? tl+1 : x)
2594#define remapy(y) (y==0 ? -1 : y==th-1 ? th+1 : y)
2595
2596void level::foreground_intersect(long x1, long y1, long &x2, long &y2)
2597{
2598/*  if (x1==x2)
2599  { vforeground_intersect(x1,y1,y2);
2600    return ;
2601  }  */
2602
2603  long tl=the_game->ftile_width(),th=the_game->ftile_height(),
2604    j,
2605    xp1,yp1,xp2,yp2,    // starting and ending points of block line segment
2606    swap;               // temp var
2607  long blockx1,blocky1,blockx2,blocky2,block,bx,by;
2608  point_list *block_list;
2609  unsigned char *bdat;
2610
2611  blockx1=x1;
2612  blocky1=y1;
2613  blockx2=x2;
2614  blocky2=y2;
2615  if (blockx1>blockx2) { swap=blockx1; blockx1=blockx2; blockx2=swap; }
2616  if (blocky1>blocky2) { swap=blocky1; blocky1=blocky2; blocky2=swap; }
2617  blockx1=(blockx1-2)/tl-1;
2618  blockx2=(blockx2+tl+2)/tl+1;
2619  blocky1=(blocky1-2)/th-1;
2620  blocky2=(blocky2+th+2)/th+1;
2621
2622
2623  if (blockx2>=foreground_width()) { x2=tl*foreground_width()-1; }
2624  if (blocky2>=foreground_height()) { y2=th*foreground_height()-1; } 
2625  blockx1=max(blockx1,0);
2626  blocky1=max(blocky1,0); 
2627
2628  if ((blockx1>blockx2) || (blocky1>blocky2)) return ;
2629
2630  // now check all the map positions this line could intersect
2631  for (bx=blockx1;bx<=blockx2;bx++)
2632  {
2633    for (by=blocky1;by<=blocky2;by++)
2634    {
2635      block=the_game->get_map_fg(bx,by);
2636      if (block>BLACK)        // don't check BLACK, should be no points in it
2637      {
2638        // now check the all the line segments in the block
2639        foretile *f=the_game->get_fg(block);
2640        block_list=f->points;
2641        unsigned char total=block_list->tot;
2642        bdat=block_list->data;
2643        unsigned char *ins=f->points->inside;
2644        long xo=bx*tl,yo=by*th;
2645        for (j=0;j<total-1;j++,ins++)
2646        {
2647          // find the starting and ending points for this segment
2648          xp1=xo+remapx(*bdat);
2649          bdat++;
2650
2651          yp1=yo+remapy(*bdat);
2652          bdat++;
2653
2654          xp2=xo+remapx(*bdat);
2655          yp2=yo+remapy(bdat[1]);
2656
2657
2658          long ox2=x2,oy2=y2;
2659          if (*ins)       
2660            setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,1);
2661          else
2662            setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,-1);
2663          if (ox2!=x2 || oy2!=y2)
2664          {
2665            last_tile_hit_x=bx;
2666            last_tile_hit_y=by;
2667          }
2668
2669        }       
2670      }
2671    }
2672  } 
2673}
2674
2675
2676void level::vforeground_intersect(long x1, long y1, long &y2)
2677{
2678  long tl=f_wid,th=f_hi,
2679    j,
2680    xp1,yp1,xp2,yp2;    // starting and ending points of block line segment temp var
2681  long blocky1,blocky2,block,bx,by,checkx;
2682  point_list *block_list;
2683  unsigned char *bdat;
2684
2685  int y_addback;
2686  if (y1>y2)
2687  {
2688    blocky1=y2/th;
2689    blocky2=y1/th;   
2690    y_addback=blocky2*f_hi;
2691  } else
2692  {
2693    blocky1=y1/th;
2694    blocky2=y2/th;
2695    y_addback=blocky1*f_hi;
2696  }
2697
2698  y1-=y_addback;
2699  y2-=y_addback;
2700
2701  bx=x1/f_wid;
2702  checkx=x1-bx*f_wid;
2703
2704
2705  // now check all the map positions this line could intersect
2706
2707  for (by=blocky1;by<=blocky2;by++,y1-=f_hi,y2-=f_hi,y_addback+=f_hi)
2708  {
2709    block=the_game->get_map_fg(bx,by);
2710
2711    // now check the all the line segments in the block
2712    foretile *f=the_game->get_fg(block);
2713    block_list=f->points;
2714
2715    unsigned char total=block_list->tot;
2716    bdat=block_list->data;
2717    unsigned char *ins=f->points->inside;
2718
2719//    long xo=bx*tl,yo=by*th;
2720    for (j=0;j<total-1;j++,ins++)
2721    {
2722      // find the starting and ending points for this segment
2723      xp1=remapx(*bdat);
2724      bdat++;
2725
2726      yp1=remapy(*bdat);
2727      bdat++;
2728
2729      xp2=remapx(*bdat);
2730      yp2=remapy(bdat[1]);
2731
2732
2733      long oy2=y2;
2734      if (*ins)   
2735        setback_intersect(checkx,y1,checkx,y2,xp1,yp1,xp2,yp2,1);
2736      else
2737        setback_intersect(checkx,y1,checkx,y2,xp1,yp1,xp2,yp2,-1);
2738      if (oy2!=y2)
2739      {
2740        last_tile_hit_x=bx;
2741        last_tile_hit_y=by;
2742      }
2743    }
2744  }
2745  y2+=y_addback;
2746}
2747
2748
2749
2750void level::send_signal(long signal)
2751{
2752  if (signal)   // signal 0 is never sent!
2753  {
2754    game_object *o=first_active;
2755    for (;o;o=o->next_active)
2756      o->recieve_signal(signal); 
2757  }
2758}
2759
2760
2761int level::crush(game_object *by_who, int xamount, int yamount)
2762{
2763  long xv,yv,crushed=0; 
2764  game_object *o=first_active;
2765  for (;o;o=o->next_active)
2766  {
2767    if (o->hurtable() && o!=by_who)
2768    {     
2769      xv=-xamount;
2770      yv=-yamount;   
2771      if (o->try_move(o->x,o->y,xv,yv,3)==by_who)
2772      {     
2773        xv=xamount;
2774        yv=yamount;
2775        o->try_move(o->x,o->y,xv,yv,3);
2776        if (xv==0 && yv==0)
2777        {
2778          if (o->state!=dead && o->state!=dieing)
2779            o->do_damage(by_who->current_figure()->hit_damage,by_who,o->x,o->y,0,0);
2780
2781/*        {           
2782            if (o->has_sequence(dieing))
2783              o->set_state(dieing);
2784            else o->set_state(dead);
2785              o->hp=0;     
2786          }         */
2787          crushed=1;     
2788        }
2789      }   
2790    }   
2791  }
2792
2793  return crushed; 
2794}
2795
2796
2797int level::platform_push(game_object *by_who, int xamount, int yamount)
2798{
2799  int failed=0;
2800  long xv,yv;
2801  game_object *o=first_active;
2802  for (;o;o=o->next_active) 
2803  {
2804    if (o->is_playable() && o->state!=dieing && o->state!=dead) 
2805    {     
2806      // check to see if the platform is going up and will run into us.     
2807      long tvx,tvy;
2808      if (yamount<0)
2809      {
2810        tvx=-xamount;
2811        tvy=-yamount;
2812        if (o->try_move(o->x,o->y,tvx,tvy,1)==by_who)
2813        {
2814          o->x+=tvx;
2815          o->y+=tvy;       
2816        }
2817      }
2818
2819/*      xv=xamount;   
2820      yv=yamount;
2821      tvx,tvy;
2822      if (xv>0) tvx=xv+1; else if (xv<0) tvx=xv-1; else tvx=0;
2823      if (yv>0) tvy=yv+1; else if (yv<0) tvx=yv-1; else tvy=0;
2824      if (o->try_move(o->x,o->y,tvx,tvy,1)==by_who)  // we the platform hit us?
2825      {
2826        o->x+=tvx;
2827        o->y+=tvy;       
2828      }*/
2829
2830      xv=0;   
2831      yv=2;
2832      if (o->try_move(o->x,o->y,xv,yv,1)==by_who)  // are we standing on the platform?
2833      {     
2834        by_who->x=-by_who->x;
2835        xv=xamount;
2836        yv=yamount;
2837        o->try_move(o->x,o->y,xv,yv,3);
2838        if (xv!=xamount || yv!=yamount) failed=1;
2839        o->x+=xv;
2840        o->y+=yv;
2841        by_who->x=-by_who->x;
2842      }   
2843    }   
2844  }
2845  return !failed;
2846}
2847
2848int level::push_characters(game_object *by_who, int xamount, int yamount)
2849{
2850  long xv,yv;
2851  int failed=0;
2852  game_object *o=first_active;
2853  for (;o;o=o->next_active) 
2854  {
2855    if ((o->is_playable() || o->pushable()) && o->state!=dieing && o->state!=dead) 
2856    {     
2857      xv=-xamount;   
2858      yv=-yamount;
2859      long tvx,tvy;
2860      if (xv>0) tvx=xv+1; else if (xv<0) tvx=xv-1; else tvx=0;
2861      if (yv>0) tvy=yv+1; else if (yv<0) tvx=yv-1; else tvy=0;
2862      if (o->try_move(o->x+xamount,o->y+yamount,tvx,tvy,3)==by_who)
2863      {     
2864        xv=(xamount-tvx);
2865        yv=(yamount-tvy);
2866        o->try_move(o->x,o->y,xv,yv,3);       
2867        o->x+=xv;
2868        o->y+=yv;
2869        if (xv!=xamount-tvx || yv!=yamount-tvy)
2870          failed=1;
2871      }   
2872    }   
2873  }
2874  return !failed;
2875}
2876
2877game_object *level::find_xrange(int x, int y, int type, int xd)
2878{
2879  long find_ydist=100000;
2880  game_object *find=NULL;
2881  game_object *o=first_active;
2882  for (;o;o=o->next_active) 
2883  {
2884    if (o->otype==type)
2885    {
2886      int x_dist=abs(x-o->x);
2887      int y_dist=abs(y-o->y);
2888
2889      if (x_dist<xd  && y_dist<find_ydist)
2890      {   
2891        find_ydist=y_dist;
2892        find=o;
2893      }
2894    }
2895  }
2896  return find;
2897}
2898
2899
2900game_object *level::find_xclosest(int x, int y, int type, game_object *who)
2901{
2902  long find_ydist=100000,find_xdist=0xffffff;
2903  game_object *find=NULL;
2904  game_object *o=first_active;
2905  for (;o;o=o->next_active) 
2906  {
2907    if (o->otype==type && o!=who)
2908    {
2909      int x_dist=abs(x-o->x);
2910      if (x_dist<find_xdist)
2911      {
2912        find_xdist=x_dist;
2913        find_ydist=abs(y-o->y);
2914        find=o;
2915      }
2916      else if (x_dist==find_xdist)
2917      {
2918        int y_dist=abs(y-o->y);
2919        if (y_dist<find_ydist)
2920        {
2921          find_ydist=y_dist;
2922          find=o;
2923        }
2924      }
2925    }
2926  }
2927  return find;
2928}
2929
2930game_object *level::find_closest(int x, int y, int type, game_object *who)
2931{
2932  long find_dist=100000;
2933  game_object *find=NULL;
2934  game_object *o=first_active;
2935  for (;o;o=o->next_active) 
2936  {
2937    if (o->otype==type && o!=who)
2938    {
2939      int d=(x-o->x)*(x-o->x)+(y-o->y)*(y-o->y);
2940      if (d<find_dist)
2941      {
2942        find=o;
2943        find_dist=d;
2944      }
2945    }
2946  }
2947  return find;
2948}
2949
2950
2951
2952void level::remove_light(light_source *which)
2953{
2954  if (which->known)
2955  {
2956    game_object *o=first;
2957    for (;o;o=o->next)
2958    {
2959      int t=o->total_lights();
2960      int i=0;
2961      for (;i<t;i++)
2962        if (o->get_light(i)==which)
2963          o->remove_light(o->get_light(i));
2964    }
2965  }
2966  delete_light(which);
2967}
2968
2969
2970game_object *level::find_type(int type, int skip)
2971{
2972  game_object *l=NULL;
2973  game_object *o=first;
2974  for (;o;o=o->next)
2975  {
2976    if (o->otype==type)
2977    {
2978      if (!skip)
2979        return o;     
2980      skip--;
2981      l=o;
2982    }
2983  }
2984  return l;
2985}
2986
2987void level::hurt_radius(long x, long y,long r, long m, game_object *from, game_object *exclude,
2988                        int max_push)
2989{
2990  if (r<1) return ;   // avoid dev vy zero
2991  game_object *o=first_active;
2992  for (;o;o=o->next_active)
2993  {
2994    if (o!=exclude && o->hurtable())
2995    {
2996      long y1=o->y,y2=o->y-o->picture()->height();
2997      long cx=abs(o->x-x),cy1=abs(y1-y),d1,d2,cy2=abs(y2-y);
2998      if (cx<cy1)
2999        d1=cx+cy1-(cx>>1);
3000      else d1=cx+cy1-(cy1>>1);
3001
3002      if (cx<cy2)
3003        d2=cx+cy2-(cx>>1);
3004      else d2=cx+cy2-(cy2>>1);
3005      if (d2<d1)
3006        d1=d2;
3007
3008
3009
3010      if (d1<r)
3011      {
3012
3013        int px=(r-cx)*max_push/r,py=(r-cy1)*max_push/r;
3014        if (o->x<x)
3015          px=-px;
3016        if (o->y<y)
3017          py=-py;
3018        o->do_damage((r-d1)*m/r,from,x,y1,px,py);
3019      }
3020
3021
3022    }
3023  }
3024
3025}
3026
3027
3028
3029game_object *level::get_random_start(int min_player_dist, view *exclude)
3030{
3031  int t=0;
3032  game_object *o=first;
3033  for (;o;o=o->next)
3034    if (o->otype==start_position_type) t++;    // count how many starts there are in the level
3035
3036  if (t==0) return NULL;                       // there aren't any starts in level!
3037
3038  int retries=t;
3039  do
3040  {
3041    int ctry=jrandom(t)+1;
3042    game_object *n=first;
3043    for (n=first;ctry && n;n=n->next)
3044    {
3045      if (n->otype==start_position_type)
3046      {
3047        o=n;
3048        ctry--;
3049      }
3050    }
3051
3052    int too_close=0;
3053    view *v=player_list;
3054    for (;v;v=v->next)
3055    {
3056      if (v!=exclude)
3057      {
3058        long cx=abs(v->x_center()-o->x),cy=abs(v->y_center()-o->y),d;
3059        if (cx<cy)
3060          d=cx+cy-(cx>>1);
3061        else d=cx+cy-(cy>>1);
3062        if (d<min_player_dist) too_close=1;
3063      }
3064    }
3065    if (too_close) retries--;
3066    else retries=0;
3067  } while (retries);
3068
3069  return o;
3070}
3071
3072
3073
3074
3075
3076void level::insert_players()
3077{
3078
3079  int start=0;
3080  int i=0;
3081  for (;i<total_objects;i++)
3082    if (!strcmp(object_names[i],"START"))
3083      start=i;
3084
3085  view *f=player_list;
3086  for (;f;f=f->next) 
3087  {
3088    game_object *st=find_type(start,f->player_number); 
3089    if (st)
3090    {
3091      f->focus->x=st->x;
3092      f->focus->y=st->y;
3093    }
3094    add_object_after(f->focus,st);
3095  }
3096
3097}
3098
3099
3100void level::add_attacker(game_object *who)
3101{
3102  if (attack_total>=attack_list_size)  // see if we need to grow the list size..
3103  {
3104    attack_list_size++;
3105    attack_list=(game_object **)jrealloc(attack_list,sizeof(game_object *)*attack_list_size,
3106                                                      "attack_list");   
3107  }
3108  attack_list[attack_total]=who;
3109  attack_total++;
3110}
3111
3112
3113
3114void level::add_target(game_object *who)
3115{
3116  if (target_total>=target_list_size)  // see if we need to grow the list size..
3117  {
3118    target_list_size++;
3119    target_list=(game_object **)jrealloc(target_list,sizeof(game_object *)*target_list_size,
3120                                                      "target_list");   
3121  }
3122  target_list[target_total]=who;
3123  target_total++;
3124}
3125
3126
3127
3128void level::add_block(game_object *who)
3129{
3130  if (block_total>=block_list_size)  // see if we need to grow the list size..
3131  {
3132    block_list_size++;
3133    block_list=(game_object **)jrealloc(block_list,sizeof(game_object *)*block_list_size,
3134                                                      "block_list");   
3135  }
3136  block_list[block_total]=who;
3137  block_total++;
3138}
3139
3140
3141void level::add_all_block(game_object *who)
3142{
3143  if (all_block_total>=all_block_list_size)  // see if we need to grow the list size..
3144  {
3145    all_block_list_size++;
3146    all_block_list=(game_object **)jrealloc(all_block_list,sizeof(game_object *)*all_block_list_size,
3147                                                      "all_block_list");   
3148  }
3149  all_block_list[all_block_total]=who;
3150  all_block_total++;
3151}
3152
3153
3154game_object *level::find_object_in_area(long x, long y, long x1, long y1, long x2, long y2,
3155                                     Cell *list, game_object *exclude)
3156{
3157  game_object *closest=NULL;
3158  long closest_distance=0xfffffff,distance,xo,yo;
3159  game_object *o=first_active;
3160  for (;o;o=o->next_active)
3161  {
3162    long xp1,yp1,xp2,yp2;
3163    o->picture_space(xp1,yp1,xp2,yp2);
3164
3165
3166    if (!(xp1>x2 || xp2<x1 || yp1>y2 || yp2<y1) && o!=exclude)
3167    {
3168      // check to see if the type is in the list
3169      Cell *v=list;
3170      for (;!NILP(v) && lnumber_value(CAR(v))!=o->otype;v=CDR(v));
3171      if (!NILP(v))
3172      {
3173        xo=abs(o->x-x);
3174        yo=abs(o->y-y);
3175        distance=xo*xo+yo*yo;
3176        if (distance<closest_distance)
3177        {
3178          closest_distance=distance;
3179          closest=o;
3180        }
3181      }
3182    }
3183  }
3184  return closest;
3185}
3186
3187
3188
3189
3190game_object *level::find_object_in_angle(long x, long y, long start_angle, long end_angle,
3191                                    void *list, game_object *exclude)
3192{
3193  game_object *closest=NULL;
3194  long closest_distance=0xfffffff,distance,xo,yo;
3195  game_object *o=first_active;
3196  for (;o;o=o->next_active)
3197  {
3198    long angle=lisp_atan2(o->y-y,o->x-x);
3199    if (((start_angle<=end_angle && (angle>=start_angle && angle<=end_angle))
3200        || (start_angle>end_angle && (angle>=start_angle || angle<=end_angle)))
3201        && o!=exclude)
3202    {
3203      // check to see if the type is in the list
3204      Cell *v=(Cell *)list;
3205      for (;!NILP(v) && lnumber_value(CAR(v))!=o->otype;v=CDR(v));
3206      if (!NILP(v))
3207      {
3208        xo=abs(o->x-x);
3209        yo=abs(o->y-y);
3210        distance=xo*xo+yo*yo;
3211        if (distance<closest_distance)
3212        {
3213          closest_distance=distance;
3214          closest=o;
3215        }
3216      }
3217    }
3218  }
3219  return closest;
3220}
3221
3222
3223object_node *level::make_not_list(object_node *list)
3224{
3225  object_node *f=NULL,*l=NULL;
3226  game_object *o=first;
3227  for (;o;o=o->next)
3228  {
3229    if (!object_to_number_in_list(o,list))
3230    {
3231      object_node *q=new object_node(o,NULL);
3232      if (f)
3233        l->next=q;
3234      else f=q;
3235      l=q;
3236    }
3237  }
3238  return f;
3239}
3240
3241FILE *open_FILE(char *filename, char *mode);
3242
3243void level::write_object_info(char *filename)
3244{
3245  FILE *fp=open_FILE(filename,"wb");
3246  if (fp)
3247  {
3248    int i=0;
3249    game_object *o=first;
3250    for (;o;o=o->next)
3251    {
3252      fprintf(fp,"%3d %s %4ld %4ld %4ld %4ld %04d\n",i++,object_names[o->otype],o->x,o->y,
3253              o->xvel(),o->yvel(),o->current_frame);
3254    }
3255    fclose(fp);
3256  }
3257}
3258
3259
3260area_controller::area_controller(long X, long Y, long W, long H, area_controller *Next)
3261{
3262  x=X; y=Y; w=W; h=H;
3263  next=Next; active=0;
3264
3265  ambient=-1;
3266  view_xoff=-1;
3267  view_yoff=-1;
3268  ambient_speed=2;
3269  view_xoff_speed=4;
3270  view_yoff_speed=4;
3271}
Note: See TracBrowser for help on using the repository browser.