Free Hero Mesh

Diff
Login
This is a mirror of the main repository for Free Hero Mesh. New tickets and changes will not be accepted at this mirror.

Differences From Artifact [bf20f83d80]:

To Artifact [a24f1b5e8f]:


82
83
84
85
86
87
88

89

90
91
92
93
94
95
96

97
98
99
100


101
102
103

104
105
106
107
108

109
110
111
112
113
114
115
82
83
84
85
86
87
88
89

90
91
92
93
94
95
96
97
98
99
100


101
102
103
104

105
106
107
108
109

110
111
112
113
114
115
116
117







+
-
+







+


-
-
+
+


-
+




-
+







    case TY_LEVELSTRING: return v.u<nlevelstrings?levelstrings[v.u]:(unsigned char*)"<Invalid level string>";
    default: fatal("Internal confusion: Trying to get string pointer for a non-string\n");
  }
}

void pfunlink(Uint32 n) {
  Object*o=objects[n];
  Uint32*pf=(o->oflags&OF_BIZARRO?bizplayfield:playfield);
  if(o->down==VOIDLINK) playfield[o->x+o->y*64-65]=o->up;
  if(o->down==VOIDLINK) pf[o->x+o->y*64-65]=o->up;
  else objects[o->down]->up=o->up;
  if(o->up!=VOIDLINK) objects[o->up]->down=o->down;
  o->down=o->up=VOIDLINK;
}

void pflink(Uint32 n) {
  Object*o=objects[n];
  Uint32*pf=(o->oflags&OF_BIZARRO?bizplayfield:playfield);
  int p=o->x+o->y*64-65;
  if(p<0) return;
  if(playfield[p]==VOIDLINK) {
    playfield[p]=n;
  if(pf[p]==VOIDLINK) {
    pf[p]=n;
  } else {
    Sint32 d=o->density;
    Uint32 m=playfield[p];
    Uint32 m=pf[p];
    Uint32 t=VOIDLINK;
    while(m!=VOIDLINK && objects[m]->density>=d) t=m,m=objects[m]->up;
    o->down=t;
    o->up=m;
    if(t!=VOIDLINK) objects[t]->up=n; else playfield[p]=n;
    if(t!=VOIDLINK) objects[t]->up=n; else pf[p]=n;
    if(m!=VOIDLINK) objects[m]->down=n;
  }
}

#define OBJECT_ARRAY_BLOCK 256
Uint32 objalloc(Uint16 c) {
  // Allocates a new object of the given class; links into the event list but not into the playfield.
208
209
210
211
212
213
214
215

216
217
218
219
220
221
222
210
211
212
213
214
215
216

217
218
219
220
221
222
223
224







-
+







      printf("# Object traced at (%d,%d)\n",o->x,o->y);
      Throw("Object traced");
    } else if(ndeadanim<0x1000 && o->anim && o->anim->status==ANISTAT_VISUAL && !(o->oflags&OF_INVISIBLE)) {
      if(o->up==VOIDLINK || (objects[o->up]->oflags&OF_DESTROYED)) set_dead_animation(o);
    }
  }
  animfree(o->anim);
  if(o->down==VOIDLINK) playfield[o->x+o->y*64-65]=o->up;
  if(o->down==VOIDLINK) (o->oflags&OF_BIZARRO?bizplayfield:playfield)[o->x+o->y*64-65]=o->up;
  else objects[o->down]->up=o->up;
  if(o->up!=VOIDLINK) objects[o->up]->down=o->down;
  if(!(o->oflags&OF_DESTROYED)) {
    if(firstobj==n) firstobj=o->next;
    if(lastobj==n) lastobj=o->prev;
    if(o->prev!=VOIDLINK) objects[o->prev]->next=o->next;
    if(o->next!=VOIDLINK) objects[o->next]->prev=o->prev;
504
505
506
507
508
509
510

511
512
513
514
515
516
517
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520







+







  v=send_message(x,y,MSG_FLOATED,NVALUE(0),NVALUE(0),NVALUE(0));
  if(!((o->oflags|p->oflags)&(OF_VISUALONLY|OF_DESTROYED))) send_message(y,x,MSG_SUNK,NVALUE(0),NVALUE(0),v);
}

static void change_density(Uint32 n,Sint32 v) {
  Object*o=objects[n];
  Uint32 i;
  if(o->oflags&OF_BIZARRO) return;
  if(v<o->density) {
    o->density=v;
    for(;;) {
      i=o->up;
      if(i==VOIDLINK || objects[i]->density<=v) return;
      sink(i,n);
    }
682
683
684
685
686
687
688

689
690
691
692
693
694
695
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699







+







  o->x=x;
  o->y=y;
  o->image=im;
  o->dir=d;
  pflink(n);
  v=send_message(from,n,MSG_CREATE,NVALUE(0),NVALUE(0),NVALUE(0));
  if(o->oflags&OF_DESTROYED) return VOIDLINK;
  if(o->oflags&OF_BIZARRO) return n;
  for(y=0;y<5;y++) for(x=0;x<5;x++) {
    xx=o->x+x-2; yy=o->y+y-2;
    if(xx<1 || xx>pfwidth || yy<1 || yy>pfheight) continue;
    i=x+5*(4-y);
    m=playfield[xx+yy*64-65];
    while(m!=VOIDLINK) {
      p=objects[m];
724
725
726
727
728
729
730
731

732
733
734
735
736
737
738
728
729
730
731
732
733
734

735
736
737
738
739
740
741
742







-
+







      if(firstobj==to) firstobj=o->next;
      if(lastobj==to) lastobj=o->prev;
      if(o->prev!=VOIDLINK) objects[o->prev]->next=o->next;
      if(o->next!=VOIDLINK) objects[o->next]->prev=o->prev;
      // This object is not itself removed from the linked list, since it may be destroyed while enumerating all objects
    }
    o->oflags|=OF_DESTROYED;
    if(why!=8 && !(o->oflags&OF_VISUALONLY)) {
    if(why!=8 && !(o->oflags&(OF_VISUALONLY|OF_BIZARRO))) {
      // Not checking for stealth; stealth only applies to movement, not destruction
      for(yy=0;yy<5;yy++) for(xx=0;xx<5;xx++) {
        x=objects[to]->x+xx-2; y=objects[to]->y+yy-2;
        if(x<1 || x>pfwidth || y<1 || y>pfheight) continue;
        i=xx+5*(4-yy);
        n=playfield[x+y*64-65];
        while(n!=VOIDLINK) {
761
762
763
764
765
766
767
768

769
770
771

772
773
774
775
776
777
778
779
780
781
782
783
784
785
786

787
788
789
790
791
792
793
794
795
796
797
798
799

800
801
802
803
804
805
806
765
766
767
768
769
770
771

772
773
774

775
776
777
778
779
780
781
782
783
784
785
786
787
788
789

790
791
792
793
794
795
796
797
798
799
800
801
802

803
804
805
806
807
808
809
810







-
+


-
+














-
+












-
+







    m=lastobj;
    while(m!=VOIDLINK) {
      if(v_bool(send_message(n,m,MSG_PLAYERMOVING,NVALUE(x),NVALUE(y),OVALUE(from)))) return 0;
      m=objects[m]->prev;
    }
  }
  if(!(o->oflags&OF_BIZARRO) && (i=classes[o->class]->collisionLayers) && (xx=collisions_at(x,y)&i)) {
    if((i=collide_with(xx,VOIDLINK,x,y,o->class))&0x01) return i&0x04?1:0;
    if((i=collide_with(xx,n,x,y,o->class))&0x01) return i&0x04?1:0;
  }
  pfunlink(n);
  if(!(o->oflags&((classes[o->class]->cflags&CF_COMPATIBLE?OF_VISUALONLY:0)|OF_STEALTHY))) {
  if(!(o->oflags&((classes[o->class]->cflags&CF_COMPATIBLE?OF_VISUALONLY:0)|OF_STEALTHY|OF_BIZARRO))) {
    for(i=25;i>=0;i--) {
      xx=o->x+Xbit(i); yy=o->y+Ybit(i);
      if(xx<1 || xx>pfwidth || yy<1 || yy>pfheight) continue;
      m=playfield[xx+yy*64-65];
      while(m!=VOIDLINK) {
        p=objects[m];
        if(p->departures&(1<<i)) p->departed|=1<<i;
        m=p->up;
      }
    }
  }
  o->distance+=abs(x-o->x)+abs(y-o->y);
  o->x=x;
  o->y=y;
  if(!(o->oflags&((classes[o->class]->cflags&CF_COMPATIBLE?OF_VISUALONLY:0)|OF_STEALTHY))) {
  if(!(o->oflags&((classes[o->class]->cflags&CF_COMPATIBLE?OF_VISUALONLY:0)|OF_STEALTHY|OF_BIZARRO))) {
    for(i=25;i>=0;i--) {
      xx=x+Xbit(i); yy=y+Ybit(i);
      if(xx<1 || xx>pfwidth || yy<1 || yy>pfheight) continue;
      m=playfield[xx+yy*64-65];
      while(m!=VOIDLINK) {
        p=objects[m];
        if(p->arrivals&(1<<i)) p->arrived|=1<<i;
        m=p->up;
      }
    }
  }
  pflink(n);
  if(!(o->oflags&OF_VISUALONLY)) {
  if(!(o->oflags&(OF_VISUALONLY|OF_BIZARRO))) {
    m=objects[n]->up;
    if(m!=VOIDLINK) {
      v=send_message(VOIDLINK,n,MSG_SUNK,NVALUE(0),NVALUE(0),NVALUE(0));
      while(m!=VOIDLINK) {
        send_message(n,m,MSG_FLOATED,NVALUE(0),NVALUE(0),v);
        m=objects[m]->up;
      }
1149
1150
1151
1152
1153
1154
1155























































































1156
1157
1158
1159
1160
1161
1162
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  }
}

static inline void flush_all(void) {
  if(current_key) all_flushed=255;
  flush_class(0);
}

static void set_bizarro(Uint32 n,Uint32 v) {
  Object*o;
  Uint8 b;
  if(n==VOIDLINK) return;
  o=objects[n];
  if(o->oflags&OF_DESTROYED) return;
  if(v) {
    if(o->oflags&OF_BIZARRO) return;
    pfunlink(n);
    o->oflags|=OF_BIZARRO;
    pflink(n);
  } else {
    if(!(o->oflags&OF_BIZARRO)) return;
    if(b=classes[o->class]->collisionLayers) {
      Uint32 m=obj_layer_at(b,o->x,o->y);
      if(m!=VOIDLINK && (collide_with(b,n,o->x,o->y,o->class)&0x01)) return;
    }
    pfunlink(n);
    o->oflags&=~OF_BIZARRO;
    pflink(n);
  }
}

void swap_world(void) {
  Uint32 n;
  int i,j,b;
  if(!main_options['e']) for(i=0;i<64*pfheight;i++) {
    n=playfield[i];
    for(b=0;n!=VOIDLINK;) {
      j=classes[objects[n]->class]->collisionLayers;
      if(b&j) Throw("SwapWorld attempted while collisions are present");
      b|=j;
      n=objects[n]->up;
    }
  }
  for(i=0;i<64*pfheight;i++) {
    n=playfield[i];
    playfield[i]=bizplayfield[i];
    bizplayfield[i]=n;
  }
  for(n=0;n<nobjects;n++) if(objects[n]) objects[n]->oflags^=OF_BIZARRO;
}

static Uint32 v_bizarro_swap(Value x,Value y) {
  Uint32 k,m,n;
  Uint8 b,c;
  if(x.t==TY_NUMBER && y.t==TY_NUMBER) {
    if(x.u<1 || x.u>pfwidth || y.u<1 || y.u>pfheight) return 0x100;
    b=c=0;
    n=bizplayfield[x.u+y.u*64-65];
    while(n!=VOIDLINK) {
      c|=b&classes[objects[n]->class]->collisionLayers;
      b|=classes[objects[n]->class]->collisionLayers;
      n=objects[n]->up;
    }
    if(c) return c;
    n=playfield[x.u+y.u*64-65];
    while(n!=VOIDLINK) objects[n]->oflags|=OF_BIZARRO,n=objects[n]->up;
    m=playfield[x.u+y.u*64-65]=bizplayfield[x.u+y.u*64-65];
    bizplayfield[x.u+y.u*64-65]=n;
    while(m!=VOIDLINK) objects[n]->oflags&=~OF_BIZARRO,m=objects[m]->up;
    return 0;
  } else {
    m=v_object(x);
    n=v_object(y);
    if(m==VOIDLINK || n==VOIDLINK || m==n) return 0x100;
    if(objects[m]->x!=objects[n]->x || objects[m]->y!=objects[n]->y) return 0x100;
    if((objects[m]->oflags|objects[n]->oflags)&OF_DESTROYED) return 0x100;
    if(!((objects[m]->oflags^objects[n]->oflags)&OF_BIZARRO)) return 0x100;
    if(objects[n]->oflags&OF_BIZARRO) k=m,m=n,n=k;
    if(b=classes[objects[m]->class]->collisionLayers) {
      k=obj_layer_at(b,objects[m]->x,objects[m]->y);
      if(k!=VOIDLINK && k!=n) {
        c=collisions_at(objects[m]->x,objects[m]->y)&b;
        if(collide_with(c,m,objects[m]->x,objects[m]->y,objects[m]->class)&0x01) return c;
      }
    }
    pfunlink(m);
    pfunlink(n);
    objects[m]->oflags^=OF_BIZARRO;
    objects[n]->oflags^=OF_BIZARRO;
    pflink(m);
    pflink(n);
    return 0;
  }
}

static inline Value v_broadcast(Uint32 from,Value c,Value msg,Value arg1,Value arg2,Value arg3,int s) {
  if(msg.t!=TY_MESSAGE) Throw("Type mismatch");
  if(c.t!=TY_CLASS && (c.t!=TY_NUMBER || c.u)) Throw("Type mismatch");
  return NVALUE(broadcast(from,c.u,msg.u,arg1,arg2,arg3,s));
}

2128
2129
2130
2131
2132
2133
2134






2135
2136
2137
2138
2139
2140
2141
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238







+
+
+
+
+
+







    case OP_ARRIVED: StackReq(0,1); Push(NVALUE(o->arrived&0x1FFFFFF)); break;
    case OP_ARRIVED_C: StackReq(1,1); Push(GetVariableOf(arrived&0x1FFFFFF,NVALUE)); break;
    case OP_ARRIVED_E: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); o->arrived=t1.u; break;
    case OP_ARRIVED_EC: NoIgnore(); StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) objects[i]->arrived=t1.u; break;
    case OP_ASSASSINATE: NoIgnore(); destroy(obj,obj,8); break;
    case OP_ASSASSINATE_C: NoIgnore(); StackReq(1,0); i=v_object(Pop()); destroy(obj,i,8); break;
    case OP_BAND: StackReq(2,1); t2=Pop(); Numeric(t2); t1=Pop(); Numeric(t1); Push(NVALUE(t1.u&t2.u)); break;
    case OP_BIZARRO: StackReq(0,1); if(o->oflags&OF_BIZARRO) Push(NVALUE(1)); else Push(NVALUE(0)); break;
    case OP_BIZARRO_C: StackReq(1,1); GetFlagOf(OF_BIZARRO); break;
    case OP_BIZARRO_E: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); set_bizarro(obj,t1.u); break;
    case OP_BIZARRO_EC: NoIgnore(); StackReq(2,0); t1=Pop(); Numeric(t1); set_bizarro(v_object(Pop()),t1.u); break;
    case OP_BIZARROSWAP: NoIgnore(); StackReq(2,1); t2=Pop(); t1=Pop(); i=v_bizarro_swap(t1,t2); Push(NVALUE(i)); break;
    case OP_BIZARROSWAP_D: NoIgnore(); StackReq(2,0); t2=Pop(); t1=Pop(); v_bizarro_swap(t1,t2); break;
    case OP_BNOT: StackReq(1,1); t1=Pop(); Numeric(t1); Push(NVALUE(~t1.u)); break;
    case OP_BOR: StackReq(2,1); t2=Pop(); Numeric(t2); t1=Pop(); Numeric(t1); Push(NVALUE(t1.u|t2.u)); break;
    case OP_BROADCAST: StackReq(4,1); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); Push(v_broadcast(obj,t1,t2,t3,t4,NVALUE(0),0)); break;
    case OP_BROADCAST_D: StackReq(4,0); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); v_broadcast(obj,t1,t2,t3,t4,NVALUE(0),0); break;
    case OP_BROADCASTAND: StackReq(4,1); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); Push(v_broadcast(obj,t1,t2,t3,t4,NVALUE(0),2)); break;
    case OP_BROADCASTANDEX: StackReq(5,1); t5=Pop(); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); Push(v_broadcast(obj,t1,t2,t3,t4,t5,2)); break;
    case OP_BROADCASTCLASS: StackReq(3,1); t4=Pop(); t3=Pop(); t2=Pop(); Push(v_broadcast(obj,CVALUE(code[ptr++]),t2,t3,t4,NVALUE(0),0)); break;
2423
2424
2425
2426
2427
2428
2429

2430
2431
2432
2433
2434
2435
2436
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534







+







    case OP_STRENGTH_EC16: NoIgnore(); StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) objects[i]->strength=t1.u&0xFFFF; break;
    case OP_STRING: StackReq(0,1); Push(UVALUE(code[ptr++],TY_STRING)); break;
    case OP_SOUND: StackReq(2,0); t2=Pop(); t1=Pop(); break; // Sound not implemented at this time
    case OP_SUB: StackReq(2,1); t2=Pop(); Numeric(t2); t1=Pop(); Numeric(t1); Push(NVALUE(t1.u-t2.u)); break;
    case OP_SUPER: i=code[1]; code=classes[i]->codes; ptr=get_message_ptr(i,msgvars.msg); if(ptr==0xFFFF) break; break;
    case OP_SUPER_C: i=code[1]; j=get_message_ptr(i,msgvars.msg); if(j!=0xFFFF) execute_program(classes[i]->codes,j,obj); break;
    case OP_SWAP: StackReq(2,2); t1=Pop(); t2=Pop(); Push(t1); Push(t2); break;
    case OP_SWAPWORLD: NoIgnore(); swap_world(); break;
    case OP_SYNCHRONIZE: StackReq(2,0); t2=Pop(); Numeric(t2); t1=Pop(); Numeric(t1); animate_sync(obj,t1.u,t2.u); break;
    case OP_TARGET: StackReq(0,1); Push(NVALUE(v_target(obj)?1:0)); break;
    case OP_TARGET_C: StackReq(1,1); i=v_object(Pop()); Push(NVALUE(v_target(i)?1:0)); break;
    case OP_TEMPERATURE: StackReq(0,1); Push(NVALUE(o->temperature)); break;
    case OP_TEMPERATURE_C: StackReq(1,1); Push(GetVariableOrAttributeOf(temperature,NVALUE)); break;
    case OP_TEMPERATURE_E: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); o->temperature=t1.u; break;
    case OP_TEMPERATURE_E16: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); o->temperature=t1.u&0xFFFF; break;
2929
2930
2931
2932
2933
2934
2935




2936
2937
2938
2939
2940






2941
2942
2943
2944
2945
2946
2947
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037





3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050







+
+
+
+
-
-
-
-
-
+
+
+
+
+
+







    turn++;
    if(!busy) all_flushed=1;
  }
  // Clock phase
  n=lastobj;
  while(n!=VOIDLINK) {
    o=objects[n];
    if(o->oflags&OF_BIZARRO) {
      o->arrived=o->departed=0;
      o->oflags&=~(OF_MOVING|OF_MOVED);
    } else {
    if(o->arrived || o->departed) goto trig;
    if(o->oflags&OF_MOVED) goto trig;
    if(o->anim && (o->anim->status&ANISTAT_LOGICAL) && (o->anim->step[o->anim->lstep].flag&ANI_ONCE)) {
      if(o->anim->ltime>=o->anim->step[o->anim->lstep].speed) goto trig;
      if(clock>o->anim->step[o->anim->lstep].speed-o->anim->ltime) clock=o->anim->step[o->anim->lstep].speed-o->anim->ltime;
      if(o->arrived || o->departed) goto trig;
      if(o->oflags&OF_MOVED) goto trig;
      if(o->anim && (o->anim->status&ANISTAT_LOGICAL) && (o->anim->step[o->anim->lstep].flag&ANI_ONCE)) {
        if(o->anim->ltime>=o->anim->step[o->anim->lstep].speed) goto trig;
        if(clock>o->anim->step[o->anim->lstep].speed-o->anim->ltime) clock=o->anim->step[o->anim->lstep].speed-o->anim->ltime;
      }
    }
    n=o->prev;
  }
  n=lastobj;
  while(n!=VOIDLINK) {
    o=objects[n];
    if(o->oflags&(OF_BUSY|OF_USERSIGNAL|OF_MOVED|OF_MOVING)) busy=1;