Free Hero Mesh

Check-in [602616bb91]
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:Complete implementation of (Order) block (mostly untested so far)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 602616bb9177bd90a0b18ce3e7475c2449979223
User & Date: user on 2021-10-14 01:14:52
Other Links: manifest | tags
Context
2021-10-15
06:47
Mention the UTI for Free Hero Mesh and improve code page documentation. (No changes to the program code.) check-in: a27d50ac26 user: user tags: trunk
2021-10-14
01:14
Complete implementation of (Order) block (mostly untested so far) check-in: 602616bb91 user: user tags: trunk
2021-10-10
00:08
More working in sound implementation (still incomplete, and some details are subject to being changed in future) check-in: 9692a28768 user: user tags: trunk
Changes

Modified TODO from [3998dd2b71] to [1a3fd7edc4].

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

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







-


















+


















+
* Game engine features
  * Multiple connected objects moving as a unit
  * String data
  * A ,PopUp command to use a popup with arguments starting from a mark
  * "Goto message" instruction (?)
  * Returning a class from COLLIDE/COLLIDEBY to transform
  * Coordinate input (may be suitable for some kind of games)
  * A way to change the order of objects execution
* Editor
  * Mouse dragging
  * Level index editor
* Table of contents for levels
  * Can define your own columns
  * User can write SQL queries on them
* Deal better with allowing to skip past corrupted levels
* Picture editor/loading
  * Allowing more altimages
  * Spare page (for temporary use while editing)
  * Batch insert multiple dependent image lumps
* Puzzle set catalog format (using with internet; a separate program)
* Inventory/replay hybrid view
* Bookmarks
* Message trace menu to enable/disable
* Bugs
  * Figure out why the $SeekerCloser class doesn't seem to work properly
  * Level 232 of SUPERHRO puzzle set (the Lava shouldn't expand? why?)
  * Animation stopping unexpectedly (until a key is pushed)
* Display solution comments/timestamp
* VCR mode
* Command-line switch for batch import/export levels
* SQL
  * Implement the GROUP column in the CLASSES table
  * Allow multiple SQL statements in one binding
* Large fonts (width 8 or 16, height 8-32)
* Branching replay recording
* Slow movement displaying state between triggers
* Warning if file changed when uncommited data exists in the cache database
* Composite puzzle set format (implemented)
  * Optional hypertext help
  * Compressed class definitions (?)
* Option to auto display level titles
* Testing
  * Bizarro world
  * Deferred movement
  * Sweep, SweepEx, HitMe
  * Overriding order of execution

Modified class.c from [459caf781d] to [f768010252].

2167
2168
2169
2170
2171
2172
2173
2174

2175
2176
2177
2178
2179
2180
2181
2167
2168
2169
2170
2171
2172
2173

2174
2175
2176
2177
2178
2179
2180
2181







-
+







  }
  if(!norders) ParseError("Empty (Order) block\n");
  orders=realloc(orders,ptr*sizeof(Uint16))?:orders;
}

static void set_class_orders(void) {
  int i,j,k;
  for(i=1;i<undef_class;i++) if(classes[i] && !(classes[i]->cflags&(CF_GROUP|CF_NOCLASS2))) {
  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;

Modified class.doc from [985a0314d5] to [22956477d6].

285
286
287
288
289
290
291
292



293
294
295
296
297
298
299
285
286
287
288
289
290
291

292
293
294
295
296
297
298
299
300
301







-
+
+
+







  32 flags can be defined in this way.

(Misc7 <userflags...>)
  Define user flags as Misc7 bits; the first defined flag is bit0. Up to
  32 flags can be defined in this way.

(Order <orders...>)
  (Not fully implemented yet.)
  See the section below about order of execution. Normally, order of
  execution (for broadcasts and some other things) is in the reverse order
  of creation; the (Order) block allows you to override this order.

(Synchronize <slot> <length> <speed>)
  Define an animation slot for synchronized animation. The slot number can
  be 0 to 7, the length is the number of images in the sequence, and the
  speed is the number of centiseconds between frames.

(Volume <number>)
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2470
2471
2472
2473
2474
2475
2476




2477
2478
2479
2480
2481
2482
2483







-
-
-
-








Trace
  Used for debugging.


=== Order of execution ===

(The below describes a feature that is not implemented yet; currently
only the syntax is implemented. When it is completed, this note will be
removed and further descriptions will be added below.)

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. This matches only classes that have that flag (changing that
flag at run time has no effect on order of execution). The remaining
2494
2495
2496
2497
2498
2499
2500





2501
2502
2503
2504
2505
2506
2507
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510







+
+
+
+
+







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.)

Note: If a value used for the criteria changes after the INIT or CREATE
message of that object returns, then it can result in an unstable (but
still fully deterministic) order when new objects are created. For this
reason, you should only use criteria based on values which don't change.


=== Compatibility ===

Compatible objects have the following differences from the default:

* VisualOnly implies Stealthy.

Modified exec.c from [85a769bf13] to [c5fcde1ccc].

664
665
666
667
668
669
670
































































































671
672
673
674
675
676
677
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773







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







        destroy(n,e[i],3);
      }
    }
    if(obj_layer_at(b,x,y)!=VOIDLINK) r|=0x01;
  }
  return r;
}

static void set_order(Uint32 obj) {
  // To avoid confusing order of execution at the wrong time,
  // calling this function is limited to only certain times.
  Object*o=objects[obj];
  Uint8 ord=classes[objects[obj]->class]->order;
  Uint8 u;
  Sint32 v0,v1;
  Uint16 p=orders[ord]+1;
  Uint32 n=firstobj;
  for(;;) {
    if(n==obj || n==VOIDLINK) goto notfound;
    u=classes[objects[n]->class]->order;
    if(u<ord) goto found;
    if(u==ord) {
      criteria: switch(orders[p]) {
        case OP_RET: goto found;
        case OP_DENSITY: v0=o->density; v1=objects[n]->density; goto compare;
        case OP_DENSITY_C: v1=o->density; v0=objects[n]->density; goto compare;
        case OP_IMAGE: v0=o->image; v1=objects[n]->image; goto compare;
        case OP_IMAGE_C: v1=o->image; v0=objects[n]->image; goto compare;
        case OP_MISC1:
          if(o->misc1.t || objects[n]->misc1.t) Throw("Type mismatch in order criteria");
          v0=o->misc1.s; v1=objects[n]->misc1.s; goto compare;
        case OP_MISC1_C:
          if(o->misc1.t || objects[n]->misc1.t) Throw("Type mismatch in order criteria");
          v1=o->misc1.s; v0=objects[n]->misc1.s; goto compare;
        case OP_MISC2:
          if(o->misc2.t || objects[n]->misc2.t) Throw("Type mismatch in order criteria");
          v0=o->misc2.s; v1=objects[n]->misc2.s; goto compare;
        case OP_MISC2_C:
          if(o->misc2.t || objects[n]->misc2.t) Throw("Type mismatch in order criteria");
          v1=o->misc2.s; v0=objects[n]->misc2.s; goto compare;
        case OP_MISC3:
          if(o->misc3.t || objects[n]->misc3.t) Throw("Type mismatch in order criteria");
          v0=o->misc3.s; v1=objects[n]->misc3.s; goto compare;
        case OP_MISC3_C:
          if(o->misc3.t || objects[n]->misc3.t) Throw("Type mismatch in order criteria");
          v1=o->misc3.s; v0=objects[n]->misc3.s; goto compare;
        case OP_MISC4:
          if(o->misc4.t || objects[n]->misc4.t) Throw("Type mismatch in order criteria");
          v0=o->misc4.s; v1=objects[n]->misc4.s; goto compare;
        case OP_MISC4_C:
          if(o->misc4.t || objects[n]->misc4.t) Throw("Type mismatch in order criteria");
          v1=o->misc4.s; v0=objects[n]->misc4.s; goto compare;
        case OP_MISC5:
          if(o->misc5.t || objects[n]->misc5.t) Throw("Type mismatch in order criteria");
          v0=o->misc5.s; v1=objects[n]->misc5.s; goto compare;
        case OP_MISC5_C:
          if(o->misc5.t || objects[n]->misc5.t) Throw("Type mismatch in order criteria");
          v1=o->misc5.s; v0=objects[n]->misc5.s; goto compare;
        case OP_MISC6:
          if(o->misc6.t || objects[n]->misc6.t) Throw("Type mismatch in order criteria");
          v0=o->misc6.s; v1=objects[n]->misc6.s; goto compare;
        case OP_MISC6_C:
          if(o->misc6.t || objects[n]->misc6.t) Throw("Type mismatch in order criteria");
          v1=o->misc6.s; v0=objects[n]->misc6.s; goto compare;
        case OP_MISC7:
          if(o->misc7.t || objects[n]->misc7.t) Throw("Type mismatch in order criteria");
          v0=o->misc7.s; v1=objects[n]->misc7.s; goto compare;
        case OP_MISC7_C:
          if(o->misc7.t || objects[n]->misc7.t) Throw("Type mismatch in order criteria");
          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;
        default: fatal("Internal confusion: Invalid order criteria (%d)\n",orders[p]);
      }
    }
    n=objects[n]->next;
  }
  found:
  // Now it has been found; insert this object previous to the found object, removing from its existing slot.
  // (Objects are executed in reverse order, so previous in the linked list means executed next)
  if(firstobj==obj) firstobj=o->next;
  if(lastobj==obj) lastobj=o->prev;
  if(o->prev!=VOIDLINK) objects[o->prev]->next=o->next;
  if(o->next!=VOIDLINK) objects[o->next]->prev=o->prev;
  o->prev=objects[n]->prev;
  o->next=n;
  objects[n]->prev=obj;
  if(o->prev==VOIDLINK) firstobj=obj;
  if(objects[n]->next==VOIDLINK) lastobj=n;
  notfound:
  objects[obj]->oflags|=OF_ORDERED;
}

static Uint32 create(Uint32 from,Uint16 c,Uint32 x,Uint32 y,Uint32 im,Uint32 d) {
  Uint32 m,n;
  int i,xx,yy;
  Object*o;
  Object*p;
  Value v;
699
700
701
702
703
704
705

706
707
708
709
710
711
712
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809







+







    while(m!=VOIDLINK) {
      p=objects[m];
      if(p->arrivals&(1<<i)) if(m!=n) send_message(n,m,MSG_CREATED,NVALUE(o->x),NVALUE(o->y),v);
      m=p->up;
    }
  }
  if(o->oflags&OF_DESTROYED) return VOIDLINK;
  if(classes[objects[n]->class]->order) set_order(n);
  m=objects[n]->up;
  if(m!=VOIDLINK) {
    v=send_message(VOIDLINK,n,MSG_SUNK,NVALUE(0),NVALUE(0),v);
    while(m!=VOIDLINK) {
      send_message(n,m,MSG_FLOATED,NVALUE(0),NVALUE(0),v);
      m=objects[m]->up;
    }
3146
3147
3148
3149
3150
3151
3152

3153
3154
3155
3156
3157
3158
3159
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257







+







  if(generation_number<=TY_MAXTYPE) return "Too many generations of objects";
  if(firstobj==VOIDLINK) return "Game cannot continue with no objects";
  // Finished
  return 0;
}

const char*init_level(void) {
  Uint32 n;
  if(setjmp(my_env)) return my_error;
  clear_inventory();
  if(main_options['t']) {
    printf("[Level %d restarted]\n",level_id);
    if(!traced_obj.t) {
      const char*s;
      optionquery[1]=Q_traceObject;
3173
3174
3175
3176
3177
3178
3179


3180




3181
3182
3183
3184
3271
3272
3273
3274
3275
3276
3277
3278
3279

3280
3281
3282
3283
3284
3285
3286
3287







+
+
-
+
+
+
+




  changed=0;
  key_ignored=0;
  all_flushed=0;
  lastimage_processing=0;
  vstackptr=0;
  move_number=0;
  current_key=0;
  n=lastobj;
  while(n!=VOIDLINK && !(objects[n]->oflags&OF_ORDERED)) {
  broadcast(VOIDLINK,0,MSG_INIT,NVALUE(0),NVALUE(0),NVALUE(0),0);
    send_message(VOIDLINK,n,MSG_INIT,NVALUE(0),NVALUE(0),NVALUE(0));
    if(classes[objects[n]->class]->order && !(objects[n]->oflags&OF_DESTROYED)) set_order(n);
    n=objects[n]->prev;
  }
  broadcast(VOIDLINK,0,MSG_POSTINIT,NVALUE(0),NVALUE(0),NVALUE(0),0);
  if(gameover) return 0;
  return execute_turn(0);
}

Modified heromesh.h from [66fec90ead] to [9e46039699].

140
141
142
143
144
145
146

147
148
149
150
151
152
153
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154







+







#define OF_MOVED 0x0040
#define OF_DONE 0x0080
#define OF_KEYCLEARED 0x0100
#define OF_DESTROYED 0x0200
#define OF_BIZARRO 0x0400
#define OF_MOVED2 0x0800
#define OF_MOVING 0x1000
#define OF_ORDERED 0x2000

typedef struct {
  const char*name;
  const char*edithelp; // not present if CF_GROUP
  const char*gamehelp; // not present if CF_GROUP
  Uint16*codes;
  Uint16*messages; // use 0xFFFF if no such message block