Free Hero Mesh

Check-in [2a3e5126fe]
Login
This is a mirror of the main repository for Free Hero Mesh. New tickets and changes will not be accepted at this mirror.
Overview
Comment:Implement much more of bizarro world (currently untested, and not implemented in level editor yet).
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 2a3e5126fe0af033a5e94d4b363319b9949042ef
User & Date: user on 2021-09-11 07:00:31
Other Links: manifest | tags
Context
2021-09-12
00:57
Implement bizarro editing. check-in: 6b326d94b8 user: user tags: trunk
2021-09-11
07:00
Implement much more of bizarro world (currently untested, and not implemented in level editor yet). check-in: 2a3e5126fe user: user tags: trunk
2021-09-09
06:18
Free Hero Mesh is starting to be bizarro. check-in: 9ded322f4f user: user tags: trunk
Changes

Modified class.c from [ca10f29396] to [8944449118].

2031
2032
2033
2034
2035
2036
2037

2038
2039
2040
2041
2042
2043
2044
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045







+







        case OP_COMPATIBLE: cl->cflags|=CF_COMPATIBLE; compat=1; break;
        case OP_COMPATIBLE_C: cl->cflags|=CF_COMPATIBLE; break;
        case OP_QUIZ: cl->cflags|=CF_QUIZ; break;
        case OP_INVISIBLE: cl->oflags|=OF_INVISIBLE; break;
        case OP_VISUALONLY: cl->oflags|=OF_VISUALONLY; break;
        case OP_STEALTHY: cl->oflags|=OF_STEALTHY; break;
        case OP_USERSTATE: cl->oflags|=OF_USERSTATE; break;
        case OP_BIZARRO: cl->oflags|=OF_BIZARRO; break;
        case OP_SHOVABLE: cl->shovable=0x55; break;
        case OP_USERFLAG: class_user_flag(cl); break;
        case OP_ABSTRACT: cl->cflags|=CF_GROUP; break;
        case 0x4000 ... 0x7FFF: set_super_class(cl,ptr); ptr=2; break;
        default: ParseError("Invalid directly inside of a class definition\n");
      }
    } else if(Tokenf(TF_CLOSE)) {

Modified class.doc from [69aafde67b] to [88620e5545].

355
356
357
358
359
360
361





362
363
364
365
366
367
368
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373







+
+
+
+
+








(Arrivals <numbers...>)
  Define the Arrivals variable for this class. This is twenty-five numbers
  each of which is either zero or one. They are meant to be on five lines
  of five numbers each, making a 5x5 matrix, where the centre means this
  object's location.

Bizarro
  Means that objects of this class created using the Create instruction
  will be created in the bizarro world by default. (This has no effect on
  objects placed in the level editor.)

(Climb <number>)
  Define the Climb variable for this class.

(CollisionLayers <numbers...>)
  Define the CollisionLayers variable for this class. The format is the
  same as for Misc4 (see below), but only the low 8-bits are usable.

832
833
834
835
836
837
838











839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854

855
856
857
858
859
860
861
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869

870
871
872
873
874
875
876
877







+
+
+
+
+
+
+
+
+
+
+















-
+







  arrivals (according to the Arrivals variable), the corresponding bits
  are set in the Arrived variable. If this value is nonzero, then it will
  also send a ARRIVED message during the trigger phase. You can write all
  bits of this variable, but only the low 25-bits can be read back; if you
  write a nonzero number with only the high bits set, then it will still
  be triggered but will be read back as zero.

Bizarro : bool [c]
  Set if this object is in the bizarro world. Objects in the bizarro world
  are invisible and intangible, and mostly do not interact with other
  objects. However, they can still be accessed/affected by anything that
  references it directly, it is still possible to broadcast messages to
  them, and they are still affected by most turn-based actions (although
  not the compatible part of the trigger phase). Objects in the bizarro
  world are effectively stealthy as well, so do not cause messages due to
  being moved, created, or destroyed. In some circumstances, attempting
  to change this flag will have no effect.

Busy : bool
  If any object has either the Busy or UserSignal variable set, then the
  player input is blocked, and the turn may continue. Use this to control
  the timing of effects in LASTIMAGE blocks.

Class : class [ro]
  The class of this object.

Climb : int16/int32 [c]
  In order for this object to move, this object's Climb must equal or
  exceed the Height of all objects at the target location, otherwise it
  is prevented from moving.

CollisionLayers : int8 [c] [ro]
  Any set bit means no other object with that same bit set in this field
  may exist at the same location.
  may exist at the same location. (There is no effect in bizarro world.)

Compatible : bool [c] [ro]
  The compatibility flag. Class definitions imported from EKS Hero Mesh
  always set this flag; in new puzzle sets it is normally not set.

Density : int16/int32 [c]
  Determines the order that objects are stacked within each cell. When an
1170
1171
1172
1173
1174
1175
1176








1177
1178
1179
1180
1181
1182
1183
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207







+
+
+
+
+
+
+
+







  Destroy the given object without sending any messages.

band  ( in1 in2 -- out )
  Bitwise AND.

(bit <numbers>)  ( -- number )
  Make a number with only the specified bits set, given numbers 0 to 31.

BizarroSwap  ( x y | obj1 obj2 -- number ) **
  Attempt to exchange either two objects (one in the bizarro world, one
  not) at the same location or all objects at the specified location into
  or out of the bizarro world. If it is successful, then the result is 0.
  If unsuccessful due to CollisionLayers, then the result is the bits in
  the CollisionLayers which are conflicting; if unsuccessful due to any
  other reason then the result will be 256.

bnot  ( in -- out )
  Bitwise NOT.

bor  ( in1 in2 -- out )
  Bitwise OR.

1737
1738
1739
1740
1741
1742
1743




1744
1745
1746
1747
1748
1749
1750
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778







+
+
+
+







  the code of the class it is inheriting.

,Super  ( ? -- ? )
  Same as Super but return to this code after it is finished.

swap  ( x y -- y x )

SwapWorld  ( -- ) **
  Exchange the entire game with the bizarro world. Sometimes, this might
  fail due to CollisionLayers bits; in this case, it is an error.

Synchronize  ( slot startimage -- ) **
  Start a synchronized animation. Give the slot number of the animation,
  and the starting image number. The length and speed are defined in a
  global definition, and the animation is always a non-oscillating loop.

Target  ( -- bool )
  Check if Arg1 and Arg2 are the coordinates of this object. It is an

Modified exec.c from [bf20f83d80] to [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;

Modified heromesh.h from [f55835fac8] to [0ccc1cadde].

274
275
276
277
278
279
280

281
282
283
284
285
286
287
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288







+







void pfunlink(Uint32 n);
void pflink(Uint32 n);
Uint32 objalloc(Uint16 c);
void objtrash(Uint32 n);
void annihilate(void);
const char*execute_turn(int key);
const char*init_level(void);
void swap_world(void);

// == game ==

extern Uint8*replay_list;
extern Uint16 replay_size,replay_count,replay_pos,replay_mark;
extern Uint8 solution_replay;

Modified instruc from [8e95d02dc6] to [11f44e42de].

303
304
305
306
307
308
309
310

311
312
313
314
315
316
317
318
319
320
303
304
305
306
307
308
309

310
311


312
313
314
315
316
317
318







-
+

-
-







-Rook
-Bishop
-Queen
-cut

; Bizarro world
,=Bizarro
.,BizarroSwap
.BizarroSwap
SwapWorld
BizarroTopAt
BizarroBottomAt

; Inheritance
-Abstract
,Super

; Specials
*Function

Modified instruc.h from [eb34a1d57f] to [2cbce0738d].

437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460











461
462
463
464
465
466
467
468
469
470
471
472
473

474
475
476
477
478
479
480
437
438
439
440
441
442
443

444

445













446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468

469
470
471
472
473
474
475
476







-

-

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












-
+







#define OP_QUEEN 32995
#define OP_CUT 32996
#define OP_BIZARRO 32997
#define OP_BIZARRO_C 35045
#define OP_BIZARRO_E 37093
#define OP_BIZARRO_EC 39141
#define OP_BIZARROSWAP 32998
#define OP_BIZARROSWAP_C 35046
#define OP_BIZARROSWAP_D 41190
#define OP_BIZARROSWAP_CD 43238
#define OP_SWAPWORLD 32999
#define OP_BIZARROTOPAT 33000
#define OP_BIZARROBOTTOMAT 33001
#define OP_ABSTRACT 33002
#define OP_SUPER 33003
#define OP_SUPER_C 35051
#define OP_FUNCTION 33004
#define OP_LOCAL 33005
#define OP_LABEL 33006
#define OP_STRING 33007
#define OP_INT16 33008
#define OP_INT32 33009
#define OP_DISPATCH 33010
#define OP_USERFLAG 33011
#define OP_ABSTRACT 33000
#define OP_SUPER 33001
#define OP_SUPER_C 35049
#define OP_FUNCTION 33002
#define OP_LOCAL 33003
#define OP_LABEL 33004
#define OP_STRING 33005
#define OP_INT16 33006
#define OP_INT32 33007
#define OP_DISPATCH 33008
#define OP_USERFLAG 33009
#ifdef HEROMESH_CLASS
static const Op_Names op_names[]={
{"*",8486939},
{"+",8421401},
{"+Move",10584239},
{"-",8421402},
{"-Move",10584240},
{"-rot",8421382},
{".",10518528},
{"/",8486940},
{"ANHH",8389394},
{"ARRIVED",8389124},
{"Abstract",8683754},
{"Abstract",8683752},
{"Animate",8421516},
{"AnimateDead",8421517},
{"Arg1",8552571},
{"Arg2",8552572},
{"Arg3",8552573},
{"Array",8683735},
{"ArrayCell",8421595},
493
494
495
496
497
498
499
500
501

502
503
504
505
506
507
508
509
489
490
491
492
493
494
495


496

497
498
499
500
501
502
503







-
-
+
-







{"BRRREEET",8389396},
{"BRRRT",8389395},
{"BUZZER",8389420},
{"BWEEP",8389397},
{"Background",8683650},
{"Bishop",8683746},
{"Bizarro",8618213},
{"BizarroBottomAt",8421609},
{"BizarroSwap",10584294},
{"BizarroSwap",10518758},
{"BizarroTopAt",8421608},
{"Broadcast",10518671},
{"BroadcastAnd",8421520},
{"BroadcastAndEx",8421521},
{"BroadcastEx",10518675},
{"BroadcastList",8421524},
{"BroadcastListEx",8421525},
{"BroadcastSum",8421526},
673
674
675
676
677
678
679
680

681
682
683
684
685
686
687
667
668
669
670
671
672
673

674
675
676
677
678
679
680
681







-
+







{"Shape",8618047},
{"ShapeDir",8618070},
{"Sharp",8618069},
{"Shovable",8618071},
{"Sound",8421571},
{"Stealthy",8618096},
{"Strength",9142354},
{"Super",8487147},
{"Super",8487145},
{"SwapWorld",8421607},
{"Synchronize",8421572},
{"TAHTASHH",8389409},
{"THMP_thmp",8389405},
{"THWIT",8389384},
{"TICK",8389391},
{"Target",8487109},
801
802
803
804
805
806
807
808

809
795
796
797
798
799
800
801

802
803







-
+

{"then",8683531},
{"tmark",8421583},
{"tuck",8421380},
{"uniq",8421590},
{"until",8683534},
{"while",8683535},
};
#define N_OP_NAMES 344
#define N_OP_NAMES 342
#endif

Modified main.c from [da2b52eaf3] to [66efb586aa].

208
209
210
211
212
213
214

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







+







  for(i=0;i<level_nindex;i++) level_index[i]=data[i+i]|(data[i+i+1]<<8);
  free(data);
}

const char*load_level(int lvl) {
  // Load level by ID. Returns null pointer if successful, or an error message if it failed.
  long sz=0;
  Uint16 of=0;
  unsigned char*buf=lvl>=0?read_lump(FIL_LEVEL,lvl,&sz):0;
  unsigned char*p=buf;
  unsigned char*end=buf+sz;
  unsigned char*q;
  int i,n,x,y,z;
  Uint16 lo=0;
  Uint32 o;
233
234
235
236
237
238
239

240
241
242
243
244
245
246


247
248
249
250
251
252
253
254

255
256
257
258
259
260
261
262
263
264
265
266
267
268





269
270
271
272
273
274
275
276
277
278

279
280
281
282
283
284
285
286
287
288
289
290
291
292
293

294
295
296
297
298
299
300
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271

272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310







+







+
+



-




+













-
+
+
+
+
+










+















+







  level_title=0;
  annihilate();
  generation_number=TY_MAXTYPE+1;
  generation_number_inc=0;
  level_version=p[0]|(p[1]<<8);
  level_code=p[2]|(p[3]<<8);
  p+=4;
  if(*p&0x80) of=OF_BIZARRO;
  pfwidth=(*p++&63)+1;
  pfheight=(*p++&63)+1;
  while(*p && p<end) p++; // skip text for now
  p++; // skip null terminator
  if(p>=end) goto bad1;
  level_title=strdup(buf+6);
  if(!level_title) fatal("Allocation failed\n");
  mru[0]=mru[1]=VOIDLINK;
  restart:
  x=0;
  y=1;
  n=0;
  mru[0]=mru[1]=VOIDLINK;
  for(;;) {
    if(n) {
      o=objalloc(objects[*mru]->class);
      if(o==VOIDLINK) goto bad3;
      objects[o]->oflags=(objects[o]->oflags&~OF_BIZARRO)|of;
      objects[o]->image=objects[*mru]->image;
      objects[o]->misc1=objects[*mru]->misc1;
      objects[o]->misc2=objects[*mru]->misc2;
      objects[o]->misc3=objects[*mru]->misc3;
      objects[o]->dir=objects[*mru]->dir;
      objects[o]->x=++x;
      objects[o]->y=y;
      if(x>pfwidth) goto bad2;
      pflink(o);
      --n;
    } else {
      if(p>=end) goto bad1;
      z=*p++;
      if(z==0xFF) break;
      if(z==0xFF) {
        if(!of) break;
        of=0;
        goto restart;
      }
      if(z&0x20) x=*p++;
      if(z&0x10) y=*p++;
      if(z&0x40) x++;
      if(!x || !y || x>pfwidth || y>pfheight) goto bad2;
      n=z&0x70?0:1;
      if(z&0x80) {
        // MRU
        if(mru[n]==VOIDLINK) goto bad1;
        o=objalloc(objects[mru[n]]->class);
        if(o==VOIDLINK) goto bad3;
        objects[o]->oflags=(objects[o]->oflags&~OF_BIZARRO)|of;
        objects[o]->image=objects[mru[n]]->image;
        objects[o]->misc1=objects[mru[n]]->misc1;
        objects[o]->misc2=objects[mru[n]]->misc2;
        objects[o]->misc3=objects[mru[n]]->misc3;
        objects[o]->dir=objects[mru[n]]->dir;
        objects[o]->x=x;
        objects[o]->y=y;
        pflink(o);
        n=z&15;
      } else {
        // Not MRU
        i=*p++;
        i|=*p++<<8;
        o=objalloc(i&0x3FFF);
        if(o==VOIDLINK) goto bad3;
        objects[o]->oflags=(objects[o]->oflags&~OF_BIZARRO)|of;
        if(n!=2) mru[n]=o;
        if(i&0x8000) {
          n=objects[o]->class;
          for(i=0;i<classes[n]->nimages;i++) {
            if(classes[n]->images[i]&0x8000) {
              objects[o]->image=i;
              break;

Modified picedit.c from [89c03fa222] to [2f3a7b5478].

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







#if 0
gcc ${CFLAGS:--s -O2} -c -Wno-multichar picedit.c `sdl-config --cflags`
gcc ${CFLAGS:--s -O2} -c -Wno-multichar -Wno-unused-result picedit.c `sdl-config --cflags`
exit
#endif

/*
  This program is part of Free Hero Mesh and is public domain.
*/

Deleted sounds.js version [3783b4826e].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72








































































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
// This program will read the sounds from HEROFALL.EXE
// The output is written to a Hamster archive to stdout
"use strict";
const hamarc=require("hamarc");
const fs=require("fs");
const out=new hamarc.File(1);
const hdr=Buffer.allocUnsafe(12);
const fil=fs.openSync(process.argv[2],"r");
const names=`
 SPLASH
 POUR
 DOOR
 GLASS
 BANG
 UNHH
 UH_OH
 FROG
 THWIT
 KLINKK
 POWER
 KLECK
 CLICK
 SMALL_POP
 DINK
 TICK
 CHYEW
 CHEEP
 ANHH
 BRRRT
 BRRREEET
 BWEEP
 DRLRLRINK
 FFFFTT
 WAHOO
 YEEHAW
 OLDPHONE
 RATTLE
 BEEDEEP
 THMP_thmp
 BEDOINGNG
 HEARTBEAT
 LOCK
 TAHTASHH
 BOOOM
 VACUUM
 RATCHET2
 DYUPE
 UNCORK
 BOUNCE
 JAYAYAYNG
 DEEP_POP
 RATCHET1
 GLISSANT
 BUZZER
 FAROUT
 KEWEL
 WHACK
 STEAM
 HAWK
`.split("\n").map(x=>x.trim()).filter(x=>x);
let n=0;
let o=process.argv[3]?parseInt(process.argv[3],16):0x5CD92;
for(;;) {
  if(fs.readSync(fil,hdr,0,12,o)<12) break;
  if(hdr.toString("ascii",0,4)!="RIFF" || hdr.toString("ascii",8,12)!="WAVE") break;
  let len=hdr.readUInt32LE(4);
  let buf=Buffer.allocUnsafeSlow(len+8);
  fs.readSync(fil,buf,0,len,o);
  out.put(names[n]+".WAV",buf);
  o+=len+8;
  n++;
}