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 [8214ecec6e]:

To Artifact [05cf8f416c]:


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
unsigned char**levelstrings;
Uint16 nlevelstrings;
Value*array_data;
Uint16 ndeadanim;
DeadAnimation*deadanim;
Uint8 no_dead_anim;
Uint32 max_trigger;


typedef struct {
  Uint16 msg;
  Uint32 from;
  Value arg1,arg2,arg3;
} MessageVars;







static jmp_buf my_env;
static const char*my_error;
static MessageVars msgvars;
static Uint8 lastimage_processing,changed,all_flushed;
static Value vstack[VSTACKSIZE];
static int vstackptr;
static const char*traceprefix;
static Uint8 current_key;
static Value quiz_obj;
static Value traced_obj;
static Uint32 control_obj=VOIDLINK;




#define Throw(x) (my_error=(x),longjmp(my_env,1))
#define StackReq(x,y) do{ if(vstackptr<(x)) Throw("Stack underflow"); if(vstackptr-(x)+(y)>=VSTACKSIZE) Throw("Stack overflow"); }while(0)
#define Push(x) (vstack[vstackptr++]=(x))
#define Pop() (vstack[--vstackptr])

// For arrival/departure masks







>






>
>
>
>
>
>












>
>
>







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
73
74
75
76
77
78
79
unsigned char**levelstrings;
Uint16 nlevelstrings;
Value*array_data;
Uint16 ndeadanim;
DeadAnimation*deadanim;
Uint8 no_dead_anim;
Uint32 max_trigger;
Uint8 conn_option;

typedef struct {
  Uint16 msg;
  Uint32 from;
  Value arg1,arg2,arg3;
} MessageVars;

typedef struct {
  Uint32 obj;
  Uint16 id;
  Uint8 visual;
} Connection;

static jmp_buf my_env;
static const char*my_error;
static MessageVars msgvars;
static Uint8 lastimage_processing,changed,all_flushed;
static Value vstack[VSTACKSIZE];
static int vstackptr;
static const char*traceprefix;
static Uint8 current_key;
static Value quiz_obj;
static Value traced_obj;
static Uint32 control_obj=VOIDLINK;
static Connection conn[VSTACKSIZE];
static int nconn,pconn;
static Uint8 conn_dir;

#define Throw(x) (my_error=(x),longjmp(my_env,1))
#define StackReq(x,y) do{ if(vstackptr<(x)) Throw("Stack underflow"); if(vstackptr-(x)+(y)>=VSTACKSIZE) Throw("Stack overflow"); }while(0)
#define Push(x) (vstack[vstackptr++]=(x))
#define Pop() (vstack[--vstackptr])

// For arrival/departure masks
947
948
949
950
951
952
953






































































































































































































































































954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969

970
971
972
973
974
975
976
  // Checks if sliding is possible, except the height of the target location.
  Uint8 m=(o->shape&(1<<d1))|(oF->shape&(1<<(4^d1)));
  if(!(m&(m-1))) return 0;
  if(!(o->shovable&(1<<d2))) return 0;
  if(height_at(o->x+x_delta[d2],o->y+y_delta[d2])<=o->climb) return 1;
  return vol+volume_at(o->x+x_delta[d2],o->y+y_delta[d2])<=max_volume;
}







































































































































































































































































static int move_dir(Uint32 from,Uint32 obj,Uint32 dir) {
  // This function is complicated, and there may be mistakes.
  Object*o;
  Object*oE;
  Object*oF;
  Object*oW;
  Uint32 objE,objF,objLF,objRF,objW;
  Uint32 hit=0;
  Uint32 vol;
  Value v;
  if(StackProtection()) Throw("Call stack overflow during movement");
  if(obj==VOIDLINK) return 0;
  oW=o=objects[objW=obj];
  o->dir=dir=resolve_dir(obj,dir);
  if(o->weight>o->inertia) goto fail;

  o->inertia-=o->weight;
  restart:
  if(hit&0x100000) dir=o->dir;
  objF=obj_dir(objW,dir);
  if(objF==VOIDLINK) goto fail;
  if(hit) hit=0x800|(hit&0x10000000);
  oF=objects[objF];







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
















>







957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
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
  // Checks if sliding is possible, except the height of the target location.
  Uint8 m=(o->shape&(1<<d1))|(oF->shape&(1<<(4^d1)));
  if(!(m&(m-1))) return 0;
  if(!(o->shovable&(1<<d2))) return 0;
  if(height_at(o->x+x_delta[d2],o->y+y_delta[d2])<=o->climb) return 1;
  return vol+volume_at(o->x+x_delta[d2],o->y+y_delta[d2])<=max_volume;
}

static int move_dir(Uint32 from,Uint32 obj,Uint32 dir);

static void add_connection(Uint32 obj) {
  Object*o=objects[obj];
  if(nconn==VSTACKSIZE) Throw("Connection limit overflow");
  if((o->oflags^OF_CONNECTION)&(OF_MOVING|OF_DESTROYED|OF_CONNECTION|OF_BIZARRO)) return;
  conn[nconn].obj=obj;
  conn[nconn].id=nconn; // used for stable sorting
  conn[nconn].visual=(o->oflags&OF_VISUALONLY)?1:0;
  o->oflags|=OF_MOVING|OF_VISUALONLY;
  nconn++;
}

static int fake_move_dir(Uint32 obj,Uint32 dir,Uint8 no) {
  // This is similar to move_dir, but specialized for the HIT/HITBY processing in connected_move.
  // Note that this may result in calling the real move_dir due to shoving.
  Object*o;
  Object*oE;
  Object*oF;
  Uint32 objE,objF,objLF,objRF;
  Uint32 hit=0;
  Uint32 vol;
  Value v;
  if(StackProtection()) Throw("Call stack overflow during movement");
  if(obj==VOIDLINK) return 0;
  o=objects[obj];
  restart:
  if(hit&0x100000) dir=o->dir;
  objF=obj_dir(obj,dir);
  if(objF==VOIDLINK) goto fail;
  if(hit) hit=0x800|(hit&0x10000000);
  oF=objects[objF];
  objLF=obj_dir(obj,(dir+1)&7);
  objRF=obj_dir(obj,(dir-1)&7);
  if(height_at(oF->x,oF->y)<=o->climb) hit|=0x200000;
  if(no) {
    if((vol=classes[oF->class]->collisionLayers) && obj_layer_at(vol,oF->x,oF->y)!=VOIDLINK) goto fail;
    hit|=0x4066;
  }
  if(dir&1) {
    // Diagonal movement
    hit|=0x80000;
    vol=o->volume;
    if(objLF!=VOIDLINK) vol+=volume_at(objects[objLF]->x,objects[objLF]->y);
    if(objRF!=VOIDLINK) vol+=volume_at(objects[objRF]->x,objects[objRF]->y);
    if(vol<=max_volume) {
      objE=objF;
      while(objE!=VOIDLINK) {
        if(o->oflags&OF_DESTROYED) break;
        oE=objects[objE];
        if(oE->height>0) {
          hit&=0xFC287040;
          v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(hit|0x81));
          if(v.t==TY_MARK) goto sticky;
          if(v.t) Throw("Type mismatch in HIT/HITBY");
          hit|=v.u;
          if(hit&8) goto fail;
          if(!(hit&0x11)) {
            v=send_message(obj,objE,MSG_HITBY,NVALUE(o->x),NVALUE(o->y),NVALUE(hit|0x81));
            if(v.t==TY_MARK) goto sticky;
            if(v.t) Throw("Type mismatch in HIT/HITBY");
            hit|=v.u;
            if(hit&8) goto fail;
          }
        }
        // Shoving
        if(!(hit&0x44) && (oE->shovable&(1<<dir)) && o->inertia>=oE->weight && !(oE->oflags&OF_VISUALONLY)) {
          oE->inertia=o->inertia;
          if(move_dir(obj,objE,dir)) {
            if(!(oE->oflags&OF_DESTROYED)) o->inertia=oE->inertia;
            hit|=0x8000;
            if(hit&0x800000) goto restart;
          }
        }
        objE=obj_below(objE);
      }
      if((hit&0x48000)==0x8000) goto restart;
      if((hit&0x200000) && !(hit&0x402008)) {
        if((hit&0x20000) || oF) goto success; else goto fail;
      }
    } else {
      // Volume is too much; hit the objects it won't go between
      if(o->oflags&OF_DESTROYED) goto fail;
      objE=objLF;
      while(objE!=VOIDLINK) {
        oE=objects[objE];
        if(oE->height>0) {
          v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(0x80089));
          if(v.t==TY_MARK) goto sticky;
          if(v.t) Throw("Type mismatch in HIT/HITBY");
          if(!(v.u&1)) v=send_message(obj,objE,MSG_HITBY,NVALUE(o->x),NVALUE(o->y),NVALUE(v.u|0x80089));
          if(v.t==TY_MARK) goto sticky;
          if(v.t==TY_SOUND || v.t==TY_USOUND) Throw("Type mismatch in HIT/HITBY");
        }
        objE=obj_below(objE);
      }
      if(o->oflags&OF_DESTROYED) goto fail;
      objE=objRF;
      while(objE!=VOIDLINK) {
        oE=objects[objE];
        if(oE->height>0) {
          v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(0x80089));
          if(v.t==TY_MARK) goto sticky;
          if(v.t) Throw("Type mismatch in HIT/HITBY");
          if(!(v.u&1)) v=send_message(obj,objE,MSG_HITBY,NVALUE(o->x),NVALUE(o->y),NVALUE(v.u|0x80089));
          if(v.t==TY_MARK) goto sticky;
          if(v.t==TY_SOUND || v.t==TY_USOUND) Throw("Type mismatch in HIT/HITBY");
        }
        objE=obj_below(objE);
      }
    }
  } else {
    // Orthogonal movement
    if(!oF) goto fail;
    objE=objF;
    while(objE!=VOIDLINK) {
      if(o->oflags&OF_DESTROYED) break;
      oE=objects[objE];
      if(oE->height>0) {
        hit&=~7;
        // HIT/HITBY messages
        v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(hit|0x81));
        if(v.t==TY_MARK) goto sticky;
        if(v.t) Throw("Type mismatch in HIT/HITBY");
        hit|=v.u;
        if(hit&8) goto fail;
        if(!(hit&0x11)) {
          v=send_message(obj,objE,MSG_HITBY,NVALUE(o->x),NVALUE(o->y),NVALUE(hit|0x81));
          if(v.t==TY_MARK) goto sticky;
          if(v.t) Throw("Type mismatch in HIT/HITBY");
          hit|=v.u;
        }
        if(hit&0x108) goto fail;
        // Hardness/sharpness
        if(!(hit&0x22)) {
          if(o->sharp[dir>>1]>oE->hard[(dir^4)>>1] && !v_bool(destroy(obj,objE,2))) hit|=0x8004;
        }
        if(hit&0x200) goto fail;
      }
      // Shoving
      if(!(hit&0x44) && (oE->shovable&(1<<dir)) && o->inertia>=oE->weight && !(oE->oflags&OF_VISUALONLY)) {
        oE->inertia=o->inertia;
        if(move_dir(obj,objE,dir)) {
          if(!(oE->oflags&OF_DESTROYED)) o->inertia=oE->inertia;
          hit|=0x8000;
          if(hit&0x800000) goto restart;
        }
      }
      if(hit&0x400) goto fail;
      objE=obj_below(objE);
    }
    if(hit&0x2008) goto fail;
    if((hit&0x48000)==0x8000) goto restart;
    if((hit&0x200000) && !(hit&0x400000)) goto success;
  }
  fail: if(hit&0x1000) goto success; o->inertia=0; return 0;
  success: return 1;
  sticky: add_connection(objE); return 2;
}

static int compare_connection(const void*v1,const void*v2) {
  // Ensure that the sorting is stable.
  const Connection*c1=v1;
  const Connection*c2=v2;
  Object*o1=objects[c1->obj];
  Object*o2=objects[c2->obj];
  switch(conn_dir) {
    case 0: case 1: return (o2->x-o1->x)?:(o1->y-o2->y)?:c2->id-c1->id; // E, NE
    case 2: case 3: return (o1->y-o2->y)?:(o1->x-o2->x)?:c2->id-c1->id; // N, NW
    case 4: case 5: return (o1->x-o2->x)?:(o2->y-o1->y)?:c2->id-c1->id; // W, SW
    case 6: case 7: return (o2->y-o1->y)?:(o2->x-o1->x)?:c2->id-c1->id; // S, SE
  }
}

static int connected_move(Uint32 obj,Uint8 dir) {
  Object*o;
  Uint32 n;
  Sint32 inertia=objects[obj]->inertia;
  Sint32 weight=0;
  int first=nconn;
  int last;
  int i,j;
  if(nconn!=pconn) Throw("Improper nested connected move");
  // Find and add all connections
  add_connection(obj);
  for(i=first;i<nconn;i++) {
    loop1:
    objects[n=conn[i].obj]->inertia=inertia;
    if(v_bool(send_message(obj,n,MSG_CONNECT,NVALUE(i-first),NVALUE(dir),NVALUE(weight)))) goto fail;
    weight+=objects[n]->weight;
  }
  if(conn_option&0x01) {
    for(i=first;i<nconn;i++) {
      o=objects[conn[i].obj];
      if(o->inertia<weight) goto fail;
      inertia-=o->weight;
    }
  } else {
    weight=objects[conn[first].obj]->weight;
  }
  last=pconn=nconn;
  // Check HIT/HITBY; may shove other objects
  if(conn_option&0x02) {
    for(i=first;i<last;i++) {
      o=objects[n=conn[i].obj];
      j=fake_move_dir(n,o->dir=dir,1);
      if(!j) goto fail;
      if(j==2) {
        if(nconn==pconn) Throw("This object cannot be sticky");
        i=pconn;
        goto loop1;
      }
    }
  }
  for(i=first;i<last;i++) {
    o=objects[n=conn[i].obj];
    if(conn_option&0x01) o->inertia=inertia;
    j=fake_move_dir(n,o->dir=dir,0);
    if(!j) goto fail;
    if((conn_option&0x01) && !(o->oflags&OF_DESTROYED)) inertia=o->inertia;
    if(j==2) {
      if(nconn==pconn) Throw("This object cannot be sticky");
      i=pconn;
      goto loop1;
    }
  }
  // Check if each object in the group is movable
  for(i=first;i<last;i++) {
    o=objects[n=conn[i].obj];
    if(v_bool(send_message(VOIDLINK,n,MSG_MOVING,NVALUE(o->x+x_delta[dir]),NVALUE(o->y+y_delta[dir]),NVALUE(0)))) goto fail;
    if(classes[o->class]->cflags&CF_PLAYER) {
      n=lastobj;
      while(n!=VOIDLINK) {
        if(v_bool(send_message(conn[i].obj,n,MSG_PLAYERMOVING,NVALUE(o->x+x_delta[dir]),NVALUE(o->y+y_delta[dir]),NVALUE(0)))) goto fail;
        n=objects[n]->prev;
      }
    }
    if(j=classes[o->class]->collisionLayers) {
      if(obj_layer_at(j,o->x+x_delta[dir],o->y+y_delta[dir])!=VOIDLINK) goto fail;
    }
  }
  // Move everything in the group
  conn_dir=dir;
  qsort(conn+first,last-first,sizeof(Connection),compare_connection);
  for(i=first;i<last;i++) {
    o=objects[n=conn[i].obj];
    if(!conn[i].visual) o->oflags&=~OF_VISUALONLY;
    if(move_to(obj,n,o->x+x_delta[dir],o->y+y_delta[dir])) o->oflags|=OF_MOVED;
  }
  // Done
  j=1; goto done;
  fail: j=0;
  done:
  for(i=first;i<nconn;i++) {
    o=objects[conn[i].obj];
    o->oflags&=~OF_MOVING;
    if(conn[i].visual) o->oflags|=OF_VISUALONLY; else o->oflags&=~OF_VISUALONLY;
  }
  pconn=nconn=first;
  return j;
}

static int move_dir(Uint32 from,Uint32 obj,Uint32 dir) {
  // This function is complicated, and there may be mistakes.
  Object*o;
  Object*oE;
  Object*oF;
  Object*oW;
  Uint32 objE,objF,objLF,objRF,objW;
  Uint32 hit=0;
  Uint32 vol;
  Value v;
  if(StackProtection()) Throw("Call stack overflow during movement");
  if(obj==VOIDLINK) return 0;
  oW=o=objects[objW=obj];
  o->dir=dir=resolve_dir(obj,dir);
  if(o->weight>o->inertia) goto fail;
  if(o->oflags&OF_CONNECTION) return connected_move(obj,dir);
  o->inertia-=o->weight;
  restart:
  if(hit&0x100000) dir=o->dir;
  objF=obj_dir(objW,dir);
  if(objF==VOIDLINK) goto fail;
  if(hit) hit=0x800|(hit&0x10000000);
  oF=objects[objF];
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
    if(objRF!=VOIDLINK) vol+=volume_at(objects[objRF]->x,objects[objRF]->y);
    if(vol<=max_volume) {
      objE=objF;
      while(objE!=VOIDLINK) {
        if(o->oflags&(OF_DESTROYED|OF_VISUALONLY)) break;
        oE=objects[objE];
        if(oE->height>0) {
          hit&=0xFC287000;
          v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(hit));
          if(v.t) Throw("Type mismatch in HIT/HITBY");
          hit|=v.u&(classes[o->class]->cflags&CF_COMPATIBLE?0xC0090F7F:-1L);
          if(hit&8) goto fail;
          if(!(hit&0x11)) {
            v=send_message(obj,objE,MSG_HITBY,NVALUE(oW->x),NVALUE(oW->y),NVALUE(hit));
            if(v.t>TY_MAXTYPE) goto warp;







|







1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
    if(objRF!=VOIDLINK) vol+=volume_at(objects[objRF]->x,objects[objRF]->y);
    if(vol<=max_volume) {
      objE=objF;
      while(objE!=VOIDLINK) {
        if(o->oflags&(OF_DESTROYED|OF_VISUALONLY)) break;
        oE=objects[objE];
        if(oE->height>0) {
          hit&=0xFC287040;
          v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(hit));
          if(v.t) Throw("Type mismatch in HIT/HITBY");
          hit|=v.u&(classes[o->class]->cflags&CF_COMPATIBLE?0xC0090F7F:-1L);
          if(hit&8) goto fail;
          if(!(hit&0x11)) {
            v=send_message(obj,objE,MSG_HITBY,NVALUE(oW->x),NVALUE(oW->y),NVALUE(hit));
            if(v.t>TY_MAXTYPE) goto warp;
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
  Object*q;
  Uint32 n;
  Uint8 x,y;
  Value v;
  if(StackProtection()) Throw("Call stack overflow during movement");
  if(obj==VOIDLINK || obj==control_obj) return 0;
  o=objects[obj];
  if(o->oflags&(OF_DESTROYED|OF_BIZARRO)) return 0;
  dir=resolve_dir(obj,dir);
  x=o->x+x_delta[dir]; y=o->y+y_delta[dir];
  if(x<1 || x>pfwidth || y<1 || y>pfheight) return 0;
  if(plus) {
    if(o->oflags&OF_MOVING) {
      if(o->dir==dir) return 1;
      v=send_message(VOIDLINK,obj,MSG_CONFLICT,NVALUE(dir),NVALUE(0),NVALUE(0));







|







1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
  Object*q;
  Uint32 n;
  Uint8 x,y;
  Value v;
  if(StackProtection()) Throw("Call stack overflow during movement");
  if(obj==VOIDLINK || obj==control_obj) return 0;
  o=objects[obj];
  if(o->oflags&(OF_DESTROYED|OF_BIZARRO|OF_CONNECTION)) return 0;
  dir=resolve_dir(obj,dir);
  x=o->x+x_delta[dir]; y=o->y+y_delta[dir];
  if(x<1 || x>pfwidth || y<1 || y>pfheight) return 0;
  if(plus) {
    if(o->oflags&OF_MOVING) {
      if(o->dir==dir) return 1;
      v=send_message(VOIDLINK,obj,MSG_CONFLICT,NVALUE(dir),NVALUE(0),NVALUE(0));
2496
2497
2498
2499
2500
2501
2502






2503
2504
2505
2506
2507
2508
2509
    case OP_CLIMB_EC16: NoIgnore(); StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) o->climb=t1.u&0xFFFF; break;
    case OP_COLLISIONLAYERS: StackReq(0,1); Push(NVALUE(classes[o->class]->collisionLayers)); break;
    case OP_COLLISIONLAYERS_C: StackReq(1,1); i=v_object(Pop()); if(i==VOIDLINK) Push(NVALUE(0)); else Push(NVALUE(classes[objects[i]->class]->collisionLayers)); break;
    case OP_COLOC: StackReq(1,1); t1=Pop(); i=colocation(obj,v_object(t1)); Push(NVALUE(i)); break;
    case OP_COLOC_C: StackReq(2,1); t1=Pop(); t2=Pop(); i=colocation(v_object(t1),v_object(t2)); Push(NVALUE(i)); break;
    case OP_COMPATIBLE: StackReq(0,1); if(classes[o->class]->cflags&CF_COMPATIBLE) Push(NVALUE(1)); else Push(NVALUE(0)); break;
    case OP_COMPATIBLE_C: StackReq(1,1); GetClassFlagOf(CF_COMPATIBLE); break;






    case OP_CONTROL: StackReq(0,1); Push(OVALUE(control_obj)); break;
    case OP_COPYARRAY: NoIgnore(); StackReq(2,0); t2=Pop(); t1=Pop(); v_copy_array(t1,t2); break;
    case OP_COUNT: StackReq(1,2); i=v_count(); Push(NVALUE(i)); break;
    case OP_CREATE: NoIgnore(); StackReq(5,1); t5=Pop(); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); Push(v_create(obj,t1,t2,t3,t4,t5)); break;
    case OP_CREATE_D: NoIgnore(); StackReq(5,0); t5=Pop(); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); v_create(obj,t1,t2,t3,t4,t5); break;
    case OP_DATA: StackReq(2,1); t2=Pop(); t1=Pop(); v_data(t1,t2); break;
    case OP_DELINVENTORY: StackReq(2,0); t2=Pop(); t1=Pop(); v_delete_inventory(t1,t2); break;







>
>
>
>
>
>







2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
    case OP_CLIMB_EC16: NoIgnore(); StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) o->climb=t1.u&0xFFFF; break;
    case OP_COLLISIONLAYERS: StackReq(0,1); Push(NVALUE(classes[o->class]->collisionLayers)); break;
    case OP_COLLISIONLAYERS_C: StackReq(1,1); i=v_object(Pop()); if(i==VOIDLINK) Push(NVALUE(0)); else Push(NVALUE(classes[objects[i]->class]->collisionLayers)); break;
    case OP_COLOC: StackReq(1,1); t1=Pop(); i=colocation(obj,v_object(t1)); Push(NVALUE(i)); break;
    case OP_COLOC_C: StackReq(2,1); t1=Pop(); t2=Pop(); i=colocation(v_object(t1),v_object(t2)); Push(NVALUE(i)); break;
    case OP_COMPATIBLE: StackReq(0,1); if(classes[o->class]->cflags&CF_COMPATIBLE) Push(NVALUE(1)); else Push(NVALUE(0)); break;
    case OP_COMPATIBLE_C: StackReq(1,1); GetClassFlagOf(CF_COMPATIBLE); break;
    case OP_CONNECT: NoIgnore(); add_connection(obj); break;
    case OP_CONNECT_C: NoIgnore(); StackReq(1,0); i=v_object(Pop()); if(i!=VOIDLINK) add_connection(i); break;
    case OP_CONNECTION: StackReq(0,1); if(o->oflags&OF_CONNECTION) Push(NVALUE(1)); else Push(NVALUE(0)); break;
    case OP_CONNECTION_C: StackReq(1,1); GetFlagOf(OF_CONNECTION); break;
    case OP_CONNECTION_E: NoIgnore(); StackReq(1,0); if(v_bool(Pop())) o->oflags|=OF_CONNECTION; else o->oflags&=~OF_CONNECTION; break;
    case OP_CONNECTION_EC: NoIgnore(); StackReq(2,0); SetFlagOf(OF_CONNECTION); break;
    case OP_CONTROL: StackReq(0,1); Push(OVALUE(control_obj)); break;
    case OP_COPYARRAY: NoIgnore(); StackReq(2,0); t2=Pop(); t1=Pop(); v_copy_array(t1,t2); break;
    case OP_COUNT: StackReq(1,2); i=v_count(); Push(NVALUE(i)); break;
    case OP_CREATE: NoIgnore(); StackReq(5,1); t5=Pop(); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); Push(v_create(obj,t1,t2,t3,t4,t5)); break;
    case OP_CREATE_D: NoIgnore(); StackReq(5,0); t5=Pop(); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); v_create(obj,t1,t2,t3,t4,t5); break;
    case OP_DATA: StackReq(2,1); t2=Pop(); t1=Pop(); v_data(t1,t2); break;
    case OP_DELINVENTORY: StackReq(2,0); t2=Pop(); t1=Pop(); v_delete_inventory(t1,t2); break;
2547
2548
2549
2550
2551
2552
2553


2554
2555
2556
2557
2558
2559
2560
    case OP_DROP: StackReq(1,0); Pop(); break;
    case OP_DROP_D: StackReq(2,0); Pop(); Pop(); break;
    case OP_DUP: StackReq(1,2); t1=Pop(); Push(t1); Push(t1); break;
    case OP_EQ: StackReq(2,1); t2=Pop(); t1=Pop(); Push(NVALUE(v_equal(t1,t2)?1:0)); break;
    case OP_EQ2: StackReq(4,1); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); Push(NVALUE(v_equal(t1,t3)?(v_equal(t2,t4)?1:0):0)); break;
    case OP_EXEC: StackReq(1,0); t1=Pop(); i=convert_link(t1,obj,code); if(i==0xFFFF) return; code=classes[i>>16]->codes; ptr=i&0xFFFF; break;
    case OP_EXEC_C: StackReq(1,0); t1=Pop(); i=convert_link(t1,obj,code); if(i!=0xFFFF) execute_program(classes[i>>16]->codes,i&0xFFFF,obj); break;


    case OP_FINISHED: StackReq(0,1); Push(NVALUE(all_flushed)); break;
    case OP_FINISHED_E: StackReq(1,0); t1=Pop(); Numeric(t1); all_flushed=t1.u; break;
    case OP_FLIP: v_flip(); break;
    case OP_FLUSHCLASS: NoIgnore(); StackReq(1,0); t1=Pop(); if(t1.t==TY_CLASS) flush_class(t1.u); else if(t1.t==TY_NUMBER && t1.s==-1) flush_all(); else if(t1.t) Throw("Type mismatch"); break;
    case OP_FLUSHOBJ: NoIgnore(); flush_object(obj); break;
    case OP_FLUSHOBJ_C: NoIgnore(); StackReq(1,0); i=v_object(Pop()); if(i!=VOIDLINK) flush_object(i); break;
    case OP_FOR: NoIgnore(); StackReq(3,1); t3=Pop(); t2=Pop(); t1=Pop(); ptr=v_for(code,ptr,t1,t2,t3); break;







>
>







2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
    case OP_DROP: StackReq(1,0); Pop(); break;
    case OP_DROP_D: StackReq(2,0); Pop(); Pop(); break;
    case OP_DUP: StackReq(1,2); t1=Pop(); Push(t1); Push(t1); break;
    case OP_EQ: StackReq(2,1); t2=Pop(); t1=Pop(); Push(NVALUE(v_equal(t1,t2)?1:0)); break;
    case OP_EQ2: StackReq(4,1); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); Push(NVALUE(v_equal(t1,t3)?(v_equal(t2,t4)?1:0):0)); break;
    case OP_EXEC: StackReq(1,0); t1=Pop(); i=convert_link(t1,obj,code); if(i==0xFFFF) return; code=classes[i>>16]->codes; ptr=i&0xFFFF; break;
    case OP_EXEC_C: StackReq(1,0); t1=Pop(); i=convert_link(t1,obj,code); if(i!=0xFFFF) execute_program(classes[i>>16]->codes,i&0xFFFF,obj); break;
    case OP_FAKEMOVE: NoIgnore(); StackReq(1,1); t1=Pop(); Numeric(t1); Push(NVALUE(fake_move_dir(obj,resolve_dir(obj,t1.u),0))); break;
    case OP_FAKEMOVE_C: NoIgnore(); StackReq(2,1); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i==VOIDLINK) Push(NVALUE(0)); else Push(NVALUE(fake_move_dir(i,resolve_dir(i,t1.u),0))); break;
    case OP_FINISHED: StackReq(0,1); Push(NVALUE(all_flushed)); break;
    case OP_FINISHED_E: StackReq(1,0); t1=Pop(); Numeric(t1); all_flushed=t1.u; break;
    case OP_FLIP: v_flip(); break;
    case OP_FLUSHCLASS: NoIgnore(); StackReq(1,0); t1=Pop(); if(t1.t==TY_CLASS) flush_class(t1.u); else if(t1.t==TY_NUMBER && t1.s==-1) flush_all(); else if(t1.t) Throw("Type mismatch"); break;
    case OP_FLUSHOBJ: NoIgnore(); flush_object(obj); break;
    case OP_FLUSHOBJ_C: NoIgnore(); StackReq(1,0); i=v_object(Pop()); if(i!=VOIDLINK) flush_object(i); break;
    case OP_FOR: NoIgnore(); StackReq(3,1); t3=Pop(); t2=Pop(); t1=Pop(); ptr=v_for(code,ptr,t1,t2,t3); break;
2946
2947
2948
2949
2950
2951
2952

2953
2954
2955
2956
2957
2958
2959
  clear_inventory();
  for(i=0;i<nlevelstrings;i++) free(levelstrings[i]);
  nlevelstrings=0;
  free(deadanim);
  deadanim=0;
  ndeadanim=0;
  control_obj=VOIDLINK;

}

static inline int try_sharp(Uint32 n1,Uint32 n2) {
  Object*o=objects[n1];
  Object*p=objects[n2];
  if((o->oflags|p->oflags)&OF_DESTROYED) return 0;
  if(o->dir&1) return 0;







>







3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
  clear_inventory();
  for(i=0;i<nlevelstrings;i++) free(levelstrings[i]);
  nlevelstrings=0;
  free(deadanim);
  deadanim=0;
  ndeadanim=0;
  control_obj=VOIDLINK;
  nconn=pconn=0;
}

static inline int try_sharp(Uint32 n1,Uint32 n2) {
  Object*o=objects[n1];
  Object*p=objects[n2];
  if((o->oflags|p->oflags)&OF_DESTROYED) return 0;
  if(o->dir&1) return 0;