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

Last change on this file since 115 was 115, checked in by Sam Hocevar, 11 years ago
  • Add lock() and unlock() methods to jimage objects. They're no-ops, but the Win32/DirectX version uses them all over the place because it uses DirectDraw? surfaces. One day we may wish to merge Abuse Win32's video output, or to use the SDL blending functions. You never know.
File size: 73.3 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 (cash.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,cash.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      cash.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    cash.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.