Free Hero Mesh

Check-in [874c691fca]
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:Allow the (Order) list to contain class names and message names.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 874c691fcadf4b08b284fcebc0f2beb5ade06ce0
User & Date: user on 2022-07-10 21:51:11
Other Links: manifest | tags
Context
2022-07-11
23:20
Improvements and corrections of pattern matching capability. check-in: cd1ff3c034 user: user tags: trunk
2022-07-10
21:51
Allow the (Order) list to contain class names and message names. check-in: 874c691fca user: user tags: trunk
00:55
Implementation of order of execution overriding is probably corrected now. check-in: 2b0b74d47a user: user tags: trunk
Changes

Modified class.c from [cc0a42cded] to [4bcfc3b7e0].

2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
    if(tokent!=TF_OPEN) ParseError("Open or close parenthesis expected\n");
    if(ptr>=0x3FFD) ParseError("Out of order memory\n");
    nxttok();
    if(Tokenf(TF_MACRO|TF_COMMA|TF_EQUAL) || !Tokenf(TF_NAME)) ParseError("Unexpected token in (Order) block\n");
    orders[++norders]=ptr;
    if(norders==beg) ParseError("Too many orders\n");
    switch(tokenv) {
      case OP_INPUT: case OP_PLAYER: case OP_CONTROL:
        orders[ptr++]=tokenv;
        break;
      case OP_USERFLAG:
        tokenv=look_hash(glohash,HASH_SIZE,0x1000,0x10FF,0,"user flags");
        if(!tokenv) ParseError("User flag ^%s not defined\n",tokenstr);
        orders[ptr++]=tokenv;
        break;







|







2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
    if(tokent!=TF_OPEN) ParseError("Open or close parenthesis expected\n");
    if(ptr>=0x3FFD) ParseError("Out of order memory\n");
    nxttok();
    if(Tokenf(TF_MACRO|TF_COMMA|TF_EQUAL) || !Tokenf(TF_NAME)) ParseError("Unexpected token in (Order) block\n");
    orders[++norders]=ptr;
    if(norders==beg) ParseError("Too many orders\n");
    switch(tokenv) {
      case OP_INPUT: case OP_PLAYER: case OP_CONTROL: case 0x4000 ... 0x7FFF:
        orders[ptr++]=tokenv;
        break;
      case OP_USERFLAG:
        tokenv=look_hash(glohash,HASH_SIZE,0x1000,0x10FF,0,"user flags");
        if(!tokenv) ParseError("User flag ^%s not defined\n",tokenstr);
        orders[ptr++]=tokenv;
        break;
2251
2252
2253
2254
2255
2256
2257

2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288








2289
2290
2291
2292
2293
2294
2295
        case OP_MISC6: case OP_MISC6_C:
        case OP_MISC7: case OP_MISC7_C:
        case OP_TEMPERATURE: case OP_TEMPERATURE_C:
        case OP_DENSITY: case OP_DENSITY_C:
        case OP_XLOC: case OP_XLOC_C:
        case OP_YLOC: case OP_YLOC_C:
        case OP_IMAGE: case OP_IMAGE_C:

          orders[ptr++]=tokenv;
          break;
        default: ParseError("Unexpected token in (Order) block\n");
      }
    }
    orders[ptr++]=OP_RET;
    nxttok();
  }
  if(!norders) ParseError("Empty (Order) block\n");
  orders=realloc(orders,ptr*sizeof(Uint16))?:orders;
}

static void set_class_orders(void) {
  int i,j,k;
  if(main_options['C']) {
    for(j=1;j<=norders;j++) {
      printf("Order %d =",j);
      k=orders[j];
      while(orders[k]!=OP_RET) printf(" %04X",orders[k++]);
      putchar('\n');
    }
  }
  for(i=1;i<undef_class;i++) if(classes[i] && (classes[i]->nmsg || classes[0]->nmsg) && !(classes[i]->cflags&(CF_GROUP|CF_NOCLASS2))) {
    for(j=1;j<=norders;j++) {
      k=orders[orders[j]];
      switch(k) {
        case 0x1000 ... 0x101F: if(classes[i]->misc4&(1UL<<(k&0x1F))) goto found; break;
        case 0x1020 ... 0x103F: if(classes[i]->misc5&(1UL<<(k&0x1F))) goto found; break;
        case 0x1040 ... 0x105F: if(classes[i]->misc6&(1UL<<(k&0x1F))) goto found; break;
        case 0x1060 ... 0x107F: if(classes[i]->misc7&(1UL<<(k&0x1F))) goto found; break;
        case 0x1080 ... 0x1087: if(classes[i]->collisionLayers&(1L<<(k&0x07))) goto found; break;








        case OP_PLAYER: if(classes[i]->cflags&CF_PLAYER) goto found; break;
        case OP_INPUT: if(classes[i]->cflags&CF_INPUT) goto found; break;
        case OP_CONTROL: if(i==control_class) goto found; break;
      }
      continue;
      found:
      classes[i]->order=j;







>













|

















>
>
>
>
>
>
>
>







2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
        case OP_MISC6: case OP_MISC6_C:
        case OP_MISC7: case OP_MISC7_C:
        case OP_TEMPERATURE: case OP_TEMPERATURE_C:
        case OP_DENSITY: case OP_DENSITY_C:
        case OP_XLOC: case OP_XLOC_C:
        case OP_YLOC: case OP_YLOC_C:
        case OP_IMAGE: case OP_IMAGE_C:
        case 0xC000 ... 0xFFFF:
          orders[ptr++]=tokenv;
          break;
        default: ParseError("Unexpected token in (Order) block\n");
      }
    }
    orders[ptr++]=OP_RET;
    nxttok();
  }
  if(!norders) ParseError("Empty (Order) block\n");
  orders=realloc(orders,ptr*sizeof(Uint16))?:orders;
}

static void set_class_orders(void) {
  int i,j,k,m;
  if(main_options['C']) {
    for(j=1;j<=norders;j++) {
      printf("Order %d =",j);
      k=orders[j];
      while(orders[k]!=OP_RET) printf(" %04X",orders[k++]);
      putchar('\n');
    }
  }
  for(i=1;i<undef_class;i++) if(classes[i] && (classes[i]->nmsg || classes[0]->nmsg) && !(classes[i]->cflags&(CF_GROUP|CF_NOCLASS2))) {
    for(j=1;j<=norders;j++) {
      k=orders[orders[j]];
      switch(k) {
        case 0x1000 ... 0x101F: if(classes[i]->misc4&(1UL<<(k&0x1F))) goto found; break;
        case 0x1020 ... 0x103F: if(classes[i]->misc5&(1UL<<(k&0x1F))) goto found; break;
        case 0x1040 ... 0x105F: if(classes[i]->misc6&(1UL<<(k&0x1F))) goto found; break;
        case 0x1060 ... 0x107F: if(classes[i]->misc7&(1UL<<(k&0x1F))) goto found; break;
        case 0x1080 ... 0x1087: if(classes[i]->collisionLayers&(1L<<(k&0x07))) goto found; break;
        case 0x4000 ... 0x7FFF:
          if(i+0x4000==k) goto found;
          m=i;
          while(m && classes[m]->codes && classes[m]->codes[0]==OP_SUPER) {
            if(classes[m]->codes[1]+0x4000==k) goto found;
            m=classes[m]->codes[1];
          }
          break;
        case OP_PLAYER: if(classes[i]->cflags&CF_PLAYER) goto found; break;
        case OP_INPUT: if(classes[i]->cflags&CF_INPUT) goto found; break;
        case OP_CONTROL: if(i==control_class) goto found; break;
      }
      continue;
      found:
      classes[i]->order=j;

Modified class.doc from [b650a160b5] to [e25de02eb2].

2777
2778
2779
2780
2781
2782
2783
2784



2785
2786
2787
2788
2789
2790
2791
2792
2793
2794










2795
2796
2797
2798
2799
2800
2801

You can specify the order of execution of objects by class by a global
(Order) block. Inside of this block is a list of sub-lists; each sub-list
is delimited by parentheses.

Each sub-list starts with a flag name, which may be a user flag, or Input,
or Player, or Control. This matches only classes that have that flag
(changing that flag at run time has no effect on order of execution).




The remaining elements are optional; if they are present, they are used to
break ties. First, the second item breaks ties if there is one, and then
if there is still a tie then the third item breaks ties, etc. These extra
elements can be one of the following, with or without a comma: Misc1,
Misc2, Misc3, Misc4, Misc5, Misc6, Misc7, Temperature, Density, Xloc, Yloc,
Image. If there is no comma, they are lowest to highest, but a comma
reverses the order to be highest to lowest instead. These values are
treated as signed, and the values after INIT or CREATE message returns is
used. If any of the values is not a number, then it is an error.











The order of execution is then first all objects not listed in the (Order)
block, and then for each sub-list in the (Order) block, the objects that
meet that criteria, in that order. (If it meets multiple criteria, only
the first one that meets that criteria is used.)

Objects not listed in the (Order) block are executed in the reverse order







|
>
>
>










>
>
>
>
>
>
>
>
>
>







2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814

You can specify the order of execution of objects by class by a global
(Order) block. Inside of this block is a list of sub-lists; each sub-list
is delimited by parentheses.

Each sub-list starts with a flag name, which may be a user flag, or Input,
or Player, or Control. This matches only classes that have that flag
(changing that flag at run time has no effect on order of execution). A
sub-list can also start with a class name, in which case only objects of
that class match; if it is an abstract class then any classes that inherit
from it (directly or indirectly) also match.

The remaining elements are optional; if they are present, they are used to
break ties. First, the second item breaks ties if there is one, and then
if there is still a tie then the third item breaks ties, etc. These extra
elements can be one of the following, with or without a comma: Misc1,
Misc2, Misc3, Misc4, Misc5, Misc6, Misc7, Temperature, Density, Xloc, Yloc,
Image. If there is no comma, they are lowest to highest, but a comma
reverses the order to be highest to lowest instead. These values are
treated as signed, and the values after INIT or CREATE message returns is
used. If any of the values is not a number, then it is an error.

Custom criteria are also possible. In this case, any of the items in the
list (other than the first one) can be a user-defined message name (but not
a built-in message). In this case, the message is sent to other objects that
match the first element of the current list to compare them. From is the
object that needs to be inserted into the list (which has just been created
or initialized), and Arg1 and Arg2 are the coordinates of that object. The
return value is negative or positive for the result of the comparison, or
zero if the result is a tie. State-changing effects are not allowed during
the processing of this message.

The order of execution is then first all objects not listed in the (Order)
block, and then for each sub-list in the (Order) block, the objects that
meet that criteria, in that order. (If it meets multiple criteria, only
the first one that meets that criteria is used.)

Objects not listed in the (Order) block are executed in the reverse order

Modified exec.c from [259ff81012] to [074e5c782f].

726
727
728
729
730
731
732

733
734
735
736
737
738
739
  // calling this function is limited to only certain times.
  Object*o=objects[obj];
  Uint8 ord=classes[o->class]->order;
  Uint8 u;
  Sint32 v0,v1;
  Uint16 p;
  Uint32 n=firstobj;

  for(;;) {
    if(n==obj || n==VOIDLINK) goto notfound;
    u=classes[objects[n]->class]->order;
    if(u<ord || !(objects[n]->oflags&OF_ORDERED)) goto found;
    if(u==ord) {
      p=orders[ord]+1;
      criteria: switch(orders[p]) {







>







726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
  // calling this function is limited to only certain times.
  Object*o=objects[obj];
  Uint8 ord=classes[o->class]->order;
  Uint8 u;
  Sint32 v0,v1;
  Uint16 p;
  Uint32 n=firstobj;
  Value v;
  for(;;) {
    if(n==obj || n==VOIDLINK) goto notfound;
    u=classes[objects[n]->class]->order;
    if(u<ord || !(objects[n]->oflags&OF_ORDERED)) goto found;
    if(u==ord) {
      p=orders[ord]+1;
      criteria: switch(orders[p]) {
786
787
788
789
790
791
792








793
794
795
796
797
798
799
          v1=o->misc7.s; v0=objects[n]->misc7.s; goto compare;
        case OP_TEMPERATURE: v0=o->temperature; v1=objects[n]->temperature; goto compare;
        case OP_TEMPERATURE_C: v1=o->temperature; v0=objects[n]->temperature; goto compare;
        case OP_XLOC: v0=o->x; v1=objects[n]->x; goto compare;
        case OP_XLOC_C: v1=o->x; v0=objects[n]->x; goto compare;
        case OP_YLOC: v0=o->y; v1=objects[n]->y; goto compare;
        case OP_YLOC_C: v1=o->y; v0=objects[n]->y; goto compare;








        compare:
          if(v0==v1) {
            p++;
            goto criteria;
          }
          if(v0>v1) goto found;
          break;







>
>
>
>
>
>
>
>







787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
          v1=o->misc7.s; v0=objects[n]->misc7.s; goto compare;
        case OP_TEMPERATURE: v0=o->temperature; v1=objects[n]->temperature; goto compare;
        case OP_TEMPERATURE_C: v1=o->temperature; v0=objects[n]->temperature; goto compare;
        case OP_XLOC: v0=o->x; v1=objects[n]->x; goto compare;
        case OP_XLOC_C: v1=o->x; v0=objects[n]->x; goto compare;
        case OP_YLOC: v0=o->y; v1=objects[n]->y; goto compare;
        case OP_YLOC_C: v1=o->y; v0=objects[n]->y; goto compare;
        case 0xC000 ... 0xFFFF: // message
          changed=0;
          v=send_message(obj,n,(orders[p]&0x3FFF)+256,NVALUE(o->x),NVALUE(o->y),NVALUE(0));
          if(changed) Throw("State-changing is not allowed during ordering");
          changed=1;
          if((o->oflags|objects[n]->oflags)&OF_DESTROYED) Throw("Destruction during ordering");
          if(v.t) Throw("Type mismatch in order criteria");
          v0=0; v1=v.s; goto compare;
        compare:
          if(v0==v1) {
            p++;
            goto criteria;
          }
          if(v0>v1) goto found;
          break;

Modified internals.doc from [e7768cb272] to [ef174d2e9e].

98
99
100
101
102
103
104

















105
106
107
108
109
110
111

The numbers of individual opcodes (with OP_ names) are not guaranteed to
remain the same between versions of Free Hero Mesh; they often change.

Some of these numbers, including the OP_ constants, are also used during
parsing; some of them occur only as tokens and not in the compiled P-code,
and some only occur in the compiled P-code and not as tokens.



















=== Text encoding ===

The control codes for text formatting are:

1-8 (\0-\7) = Colours







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







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

The numbers of individual opcodes (with OP_ names) are not guaranteed to
remain the same between versions of Free Hero Mesh; they often change.

Some of these numbers, including the OP_ constants, are also used during
parsing; some of them occur only as tokens and not in the compiled P-code,
and some only occur in the compiled P-code and not as tokens.

Any class that inherits from another class starts with OP_SUPER and then
the class number that it inherits from (which must be an abstract class).
(Note this is the raw class number and is not the opcode number.)


=== Orders ===

The orders array is arranged as follows:

* Index zero is not used.

* After that, each entry, with the index being the order number, will be
the index within the orders array where the specification starts at.

* Each specification simply consists of the opcode numbers and is
terminated by OP_RET.


=== Text encoding ===

The control codes for text formatting are:

1-8 (\0-\7) = Colours