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

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