Free Hero Mesh

Check-in [60b09ee8e4]
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 returning classes/objects from COLLIDEBY message to transform objects. (Not fully tested yet)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 60b09ee8e4735d9f6273c8b70be6cbfa4df3991e
User & Date: user on 2022-10-19 22:28:12
Other Links: manifest | tags
Context
2022-11-07
07:29
Additions to FAQ. check-in: ef8fe744ff user: user tags: trunk
2022-10-19
22:28
Implement returning classes/objects from COLLIDEBY message to transform objects. (Not fully tested yet) check-in: 60b09ee8e4 user: user tags: trunk
2022-10-05
23:26
Implement LastR, NextR, ThisR; this is not tested and not fully complete; it will be used in future to implement replacing objects with new ones in COLLIDE and COLLIDEBY messages. check-in: 1114ae75d5 user: user tags: trunk
Changes

Modified TODO from [f100d9392d] to [2f82fa955d].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
* Sound effects
  * Compressed wave sounds (?)
  * Numeric sounds (?)
* Game engine features
  * String data (partially implemented)
  * A ,PopUp command to use a popup with arguments starting from a mark
  * Returning a class from COLLIDE/COLLIDEBY to transform
  * Possibility to define auto-generation levels mode
  * Popup inventory list (with optional possibility of choice) (?)
  * Playfield array
* Editor
  * Mouse dragging
* Deal better with allowing to skip past corrupted levels
* Picture editor/loading






<







1
2
3
4
5
6

7
8
9
10
11
12
13
* Sound effects
  * Compressed wave sounds (?)
  * Numeric sounds (?)
* Game engine features
  * String data (partially implemented)
  * A ,PopUp command to use a popup with arguments starting from a mark

  * Possibility to define auto-generation levels mode
  * Popup inventory list (with optional possibility of choice) (?)
  * Playfield array
* Editor
  * Mouse dragging
* Deal better with allowing to skip past corrupted levels
* Picture editor/loading
48
49
50
51
52
53
54

55
56
57
58
59
60
61
62
63
64
65
66
* Multiuser scoring within one computer system (optional capability)
* Launcher menu (optional; separate program)
* Testing
  * Bizarro world
  * Connection movement (it is partially tested, already)
  * Sweep, SweepEx, HitMe
  * Overriding order of execution (partially tested)

* Conversion from other games
  * DOS Hero Hearts
  * Berusky
  * PC Wanderer
  * Escape
  * Chroma
  * Xsok
  * PuzzleScript (limited; not everything is or will be capable)
  * Sokoban
  * Puzzle Boy
  * Pitman/Catrap
* Improve build system







>












47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
* Multiuser scoring within one computer system (optional capability)
* Launcher menu (optional; separate program)
* Testing
  * Bizarro world
  * Connection movement (it is partially tested, already)
  * Sweep, SweepEx, HitMe
  * Overriding order of execution (partially tested)
  * Returning classes/objects from COLLIDEBY
* Conversion from other games
  * DOS Hero Hearts
  * Berusky
  * PC Wanderer
  * Escape
  * Chroma
  * Xsok
  * PuzzleScript (limited; not everything is or will be capable)
  * Sokoban
  * Puzzle Boy
  * Pitman/Catrap
* Improve build system

Modified class.doc from [8db1014969] to [d0a4a4775b].

708
709
710
711
712
713
714

715
716
717
718
719
720
721
  LASTIMAGE
  MOVED
  MOVING
  NEXTWARP
  PLAYERMOVING
  POSTINIT
  SUNK


Input constants:
  'BACK = 8
  'TAB = 9
  'CENTER = 12
  'ENTER = 13
  'SHIFT = 16







>







708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
  LASTIMAGE
  MOVED
  MOVING
  NEXTWARP
  PLAYERMOVING
  POSTINIT
  SUNK
  XCREATE

Input constants:
  'BACK = 8
  'TAB = 9
  'CENTER = 12
  'ENTER = 13
  'SHIFT = 16
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
  object. The direction of movement is specified by the Dir variable.
  This flag is also used for connected movement, for a different purpose.

NextR : any
  This variable is normally zero, but when there is a collision by the
  CollisionLayers, it can be programmed to destroy an object and create
  another one which represents the combination of the two. In this case,
  the NextR variable of the destroyed object points to the new one. (Note:
  This feature is not yet fully implemented.)

Player : bool [c] [ro]
  If this object is the player. This is used implicitly as the From of
  some messages sent by the game engine, and has a few other purposes.
  (Normally, a level should have exactly one object of such a class,
  although this is not mandatory; any number (including zero) is allowed.)








|
<







1073
1074
1075
1076
1077
1078
1079
1080

1081
1082
1083
1084
1085
1086
1087
  object. The direction of movement is specified by the Dir variable.
  This flag is also used for connected movement, for a different purpose.

NextR : any
  This variable is normally zero, but when there is a collision by the
  CollisionLayers, it can be programmed to destroy an object and create
  another one which represents the combination of the two. In this case,
  the NextR variable of the destroyed object points to the new one.


Player : bool [c] [ro]
  If this object is the player. This is used implicitly as the From of
  some messages sent by the game engine, and has a few other purposes.
  (Normally, a level should have exactly one object of such a class,
  although this is not mandatory; any number (including zero) is allowed.)

2395
2396
2397
2398
2399
2400
2401
2402





2403
2404
2405
2406
2407
2408
2409
  Of the return value, bit0 means to prevent the movement, bit1 means to
  not send any more COLLIDEBY messages, bit2 means to pretend the movement
  attempt is successful even if it isn't (there is no effect for creating
  objects; this bit is meaningful only for moves), and bit4 means that if
  necessary, it will try to destroy this object to make room. From is the
  object attempting to move here, and Arg1 and Arg2 are its location (if
  attempting to create an object, then From, Arg1, and Arg2 are all zero).
  Arg3 is the class of the object being moved or created.






COLLIDING
  Called when deferred movement is being performed if the move cannot
  occur due to a collision with some other object. From is the object
  that it is colliding with, Arg1 and Arg2 are its location, and Arg3
  is the type of collision (0 if this object is trying to move into a
  stationary object, 1 if another object is trying to move into this







|
>
>
>
>
>







2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
  Of the return value, bit0 means to prevent the movement, bit1 means to
  not send any more COLLIDEBY messages, bit2 means to pretend the movement
  attempt is successful even if it isn't (there is no effect for creating
  objects; this bit is meaningful only for moves), and bit4 means that if
  necessary, it will try to destroy this object to make room. From is the
  object attempting to move here, and Arg1 and Arg2 are its location (if
  attempting to create an object, then From, Arg1, and Arg2 are all zero).
  Arg3 is the class of the object being moved or created. If the return
  value is a class, then it will destroy this one, and if moving also the
  object moving, and attempt to create an object of the specified class
  instead and set the NextR of both old objects to the new one. If the
  return value is an object, it is treated as 1 but creation will return
  the specified object instead of the one which is trying to be created.

COLLIDING
  Called when deferred movement is being performed if the move cannot
  occur due to a collision with some other object. From is the object
  that it is colliding with, Arg1 and Arg2 are its location, and Arg3
  is the type of collision (0 if this object is trying to move into a
  stationary object, 1 if another object is trying to move into this
2435
2436
2437
2438
2439
2440
2441
2442


2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459




2460

2461
2462
2463
2464
2465
2466
2467
  the Inertia is not automatically changed.

CREATE
  Sent when the object is created by the Create instruction. This is done
  after the object is created, but before sending any other messages. The
  From is the object that created it. The return value will be used as the
  Arg3 of the SUNK and CREATED messages it might send if appropriate. From
  is the object which executed the Create instruction to create it.



CREATED
  Sent to all objects whose Arrivals care about objects in the location
  where an object has just been created. From is the newly created object,
  Arg1 and Arg2 are the X and Y coordinates where the object was created,
  and Arg3 is the return value from the CREATE message.

DEPARTED
  Sent during the trigger phase if the Departed value is nonzero. Arg1 is
  the saved Departed value. The Departed variable will usually be set
  automatically; see the section about variables.

DESTROY
  Received when the object is about to be destroyed. Arg3 is the reason:
  0 for the Destroy or ,Destroy instruction, 1 due to this object moving
  into something sharp, 2 due to something sharp moving into this one,
  3 for a conflict with CollisionLayers, or 4 for crushing. The return




  value is false to allow it to be destroyed or true to keep the object.


DESTROYED
  Sent to all objects whose Departures care about objects in the location
  where an object has just been destroyed (if its VisualOnly flag isn't
  set). From is the object which has just been destroyed. Arg3 is the
  reason, as for the DESTROY message.








|
>
>
















|
>
>
>
>
|
>







2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
  the Inertia is not automatically changed.

CREATE
  Sent when the object is created by the Create instruction. This is done
  after the object is created, but before sending any other messages. The
  From is the object that created it. The return value will be used as the
  Arg3 of the SUNK and CREATED messages it might send if appropriate. From
  is the object which executed the Create instruction to create it, or zero
  if it was sent after a XCREATE message due to objects being replaced
  after a collision.

CREATED
  Sent to all objects whose Arrivals care about objects in the location
  where an object has just been created. From is the newly created object,
  Arg1 and Arg2 are the X and Y coordinates where the object was created,
  and Arg3 is the return value from the CREATE message.

DEPARTED
  Sent during the trigger phase if the Departed value is nonzero. Arg1 is
  the saved Departed value. The Departed variable will usually be set
  automatically; see the section about variables.

DESTROY
  Received when the object is about to be destroyed. Arg3 is the reason:
  0 for the Destroy or ,Destroy instruction, 1 due to this object moving
  into something sharp, 2 due to something sharp moving into this one,
  3 for a conflict with CollisionLayers, 4 for crushing, 5 if it was
  destroyed due to COLLIDEBY returning a class or object to be created
  in its place to substitute for it, or 6 if it was trying to move into
  another place but could not and COLLIDEBY told it to create a different
  object in its place (in which case From is the object that it collided
  with). The return value is false to allow it to be destroyed or true to
  keep the object.

DESTROYED
  Sent to all objects whose Departures care about objects in the location
  where an object has just been destroyed (if its VisualOnly flag isn't
  set). From is the object which has just been destroyed. Arg3 is the
  reason, as for the DESTROY message.

2574
2575
2576
2577
2578
2579
2580













2581
2582
2583
2584
2585
2586
2587
  has been exchanged with. Arg3 is the return value from the corresponding
  FLOATED message. The other cases this is used is when an object moves or
  is created but is not the least dense object at that location. In this
  case, From is zero, and the return value is not used. For creation, Arg3
  is the return value of the corresponding CREATE message; for movement,
  Arg3 is always zero. (This has nothing to do with sinking in water.)















=== Hit values ===

This section describes the bits of the return value of the HIT and HITBY
messages; these values are also used as the Arg3 of those messages.

Some descriptions below are marked with an asterisk. If the Compatible







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







2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
  has been exchanged with. Arg3 is the return value from the corresponding
  FLOATED message. The other cases this is used is when an object moves or
  is created but is not the least dense object at that location. In this
  case, From is zero, and the return value is not used. For creation, Arg3
  is the return value of the corresponding CREATE message; for movement,
  Arg3 is always zero. (This has nothing to do with sinking in water.)

XCREATE
  This message is received by an object which has been just created due to
  a COLLIDEBY message returning a class. From is the object at the target
  location that a collision with layers occurred (which is now destroyed).
  Arg1 is the class of the attempted creation or object trying to move
  here, Arg2 is the image of the attempted creation or object trying to
  move here, and Arg3 is the object trying to move here (or zero if it was
  trying to create an object). If the return value is zero, then it will
  continue with CREATE, CREATED, SUNK, and FLOATED messages like with a
  usual creation, but if a number other than zero then they are skipped.
  If the return value is an object, then the Create command will return
  the specified object.


=== Hit values ===

This section describes the bits of the return value of the HIT and HITBY
messages; these values are also used as the Arg3 of those messages.

Some descriptions below are marked with an asterisk. If the Compatible

Modified exec.c from [e8eae091e5] to [95d75eb122].

67
68
69
70
71
72
73


74
75
76
77
78
79
80
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







>
>







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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;
static Uint16 subst_class;
static Uint32 subst_obj;

#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
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
  while(n!=VOIDLINK) {
    if(!(objects[n]->oflags&OF_DESTROYED)) c|=classes[objects[n]->class]->collisionLayers;
    n=objects[n]->up;
  }
  return c;
}

static Uint8 collide_with(Uint8 b,Uint32 n,Uint8 x,Uint8 y,Uint16 c) {
  int i,j;
  Uint8 r=0;
  Uint32 e[8]={VOIDLINK,VOIDLINK,VOIDLINK,VOIDLINK,VOIDLINK,VOIDLINK,VOIDLINK,VOIDLINK};
  Uint8 re[8]={0,0,0,0,0,0,0,0};
  Value v;
  if(StackProtection()) Throw("Call stack overflow");
  for(i=0;i<8;i++) if(b&(1<<i)) e[i]=obj_layer_at(1<<i,x,y);
  for(i=0;i<7;i++) for(j=i+1;j<8;j++) if(e[i]==e[j]) e[j]=VOIDLINK;
  if(n!=VOIDLINK) {
    v=send_message(VOIDLINK,n,MSG_COLLIDE,NVALUE(x),NVALUE(y),NVALUE(b));
    if(v.t) Throw("Type mismatch in COLLIDE");
    r=v.u;
  }
  for(i=0;i<8;i++) if(e[i]!=VOIDLINK && !(r&0x02)) {
    v=send_message(n,e[i],MSG_COLLIDEBY,NVALUE(n==VOIDLINK?0:objects[n]->x),NVALUE(n==VOIDLINK?0:objects[n]->y),CVALUE(c));









    if(v.t) Throw("Type mismatch in COLLIDEBY");
    r|=re[i]=v.u;
  }
  if(!(r&0x01)) {
    // See if we can destroy some objects to make room
    b=classes[c]->collisionLayers;
    if(obj_layer_at(b,x,y)==VOIDLINK) return r;







|















>
>
>
>
>
>
>
>
>







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
  while(n!=VOIDLINK) {
    if(!(objects[n]->oflags&OF_DESTROYED)) c|=classes[objects[n]->class]->collisionLayers;
    n=objects[n]->up;
  }
  return c;
}

static Uint16 collide_with(Uint8 b,Uint32 n,Uint8 x,Uint8 y,Uint16 c) {
  int i,j;
  Uint8 r=0;
  Uint32 e[8]={VOIDLINK,VOIDLINK,VOIDLINK,VOIDLINK,VOIDLINK,VOIDLINK,VOIDLINK,VOIDLINK};
  Uint8 re[8]={0,0,0,0,0,0,0,0};
  Value v;
  if(StackProtection()) Throw("Call stack overflow");
  for(i=0;i<8;i++) if(b&(1<<i)) e[i]=obj_layer_at(1<<i,x,y);
  for(i=0;i<7;i++) for(j=i+1;j<8;j++) if(e[i]==e[j]) e[j]=VOIDLINK;
  if(n!=VOIDLINK) {
    v=send_message(VOIDLINK,n,MSG_COLLIDE,NVALUE(x),NVALUE(y),NVALUE(b));
    if(v.t) Throw("Type mismatch in COLLIDE");
    r=v.u;
  }
  for(i=0;i<8;i++) if(e[i]!=VOIDLINK && !(r&0x02)) {
    v=send_message(n,e[i],MSG_COLLIDEBY,NVALUE(n==VOIDLINK?0:objects[n]->x),NVALUE(n==VOIDLINK?0:objects[n]->y),CVALUE(c));
    if(v.t==TY_CLASS) {
      subst_class=v.u;
      subst_obj=e[i];
      return 0x8001;
    } else if(v.t>TY_MAXTYPE) {
      subst_class=0;
      subst_obj=v_object(v);
      return 0x8001;
    }
    if(v.t) Throw("Type mismatch in COLLIDEBY");
    r|=re[i]=v.u;
  }
  if(!(r&0x01)) {
    // See if we can destroy some objects to make room
    b=classes[c]->collisionLayers;
    if(obj_layer_at(b,x,y)==VOIDLINK) return r;
819
820
821
822
823
824
825
826















































































827
828
829
830
831
832
833
834
835
836














837
838
839
840
841
842
843
  o->next=n;
  o->prev=objects[n]->prev;
  objects[n]->prev=obj;
  if(o->prev==VOIDLINK) firstobj=obj; else objects[o->prev]->next=obj;
  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;
  if(d>7) d=0;
  if(x<1 || y<1 || x>pfwidth || y>pfheight || c==control_class) return VOIDLINK;
  if(!(classes[c]->oflags&OF_BIZARRO) && (i=classes[c]->collisionLayers) && (xx=collisions_at(x,y)&i)) {
    if(collide_with(xx,VOIDLINK,x,y,c)&0x01) return VOIDLINK;














  }
  n=objalloc(c);
  if(n==VOIDLINK) Throw("Error creating object");
  o=objects[n];
  o->x=x;
  o->y=y;
  o->image=im;








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









|
>
>
>
>
>
>
>
>
>
>
>
>
>
>







830
831
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
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
  o->next=n;
  o->prev=objects[n]->prev;
  objects[n]->prev=obj;
  if(o->prev==VOIDLINK) firstobj=obj; else objects[o->prev]->next=obj;
  notfound:
  objects[obj]->oflags|=OF_ORDERED;
}

static Uint32 x_create(Uint32 from,Uint16 c,Uint32 x,Uint32 y,Uint32 d,Value arg1,Value arg2,Value arg3) {
  // This function is only called if x and y and d are already verified to be valid, so need not be checked again.
  Uint32 m,n;
  int i,xx,yy;
  Object*o;
  Object*p;
  Value v;
  if(c==control_class || !c) return VOIDLINK;
  // Although this function can be called recursively, StackProtection() is unnecessary,
  // because in the case that it is called recursively, it is guaranteed to call either
  // collide_with or execute_program (indirectly), which then calls StackProtection().
  if((i=classes[c]->collisionLayers) && (xx=collisions_at(x,y)&i)) {
    if((i=collide_with(xx,VOIDLINK,x,y,c))&0x01) {
      if(i&0x8000) {
        if(subst_class) {
          m=subst_obj;
          v=destroy(VOIDLINK,m,5);
          if(v.t) return VOIDLINK;
          n=x_create(m,subst_class,x,y,d,arg1,arg2,arg3);
          if(n!=VOIDLINK) objects[from]->replacement=objects[m]->replacement=OVALUE(n);
          return n;
        } else {
          return subst_obj;
        }
      }
      return VOIDLINK;
    }
  }
  n=objalloc(c);
  if(n==VOIDLINK) Throw("Error creating object");
  o=objects[n];
  o->x=x;
  o->y=y;
  o->image=0;
  o->dir=d;
  o->oflags&=~OF_BIZARRO;
  objects[from]->replacement=OVALUE(n);
  pflink(n);
  v=send_message(from,n,MSG_XCREATE,arg1,arg2,arg3);
  if(v.t>TY_MAXTYPE) {
    if(classes[objects[n]->class]->order && !(o->oflags&OF_DESTROYED)) set_order(n);
    return v_object(v);
  } else if(v.t) {
    Throw("Type mismatch");
  }
  if(o->oflags&OF_DESTROYED) return VOIDLINK;
  if(v.u) goto skip;
  v=send_message(VOIDLINK,n,MSG_CREATE,NVALUE(0),NVALUE(0),NVALUE(0));
  if(o->oflags&OF_DESTROYED) return VOIDLINK;
  if(o->oflags&OF_BIZARRO) {
    skip:
    if(classes[objects[n]->class]->order) set_order(n);
    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];
      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;
    }
  }
  if(o->oflags&OF_DESTROYED) return VOIDLINK;
  return n;
}

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;
  if(d>7) d=0;
  if(x<1 || y<1 || x>pfwidth || y>pfheight || c==control_class) return VOIDLINK;
  if(!(classes[c]->oflags&OF_BIZARRO) && (i=classes[c]->collisionLayers) && (xx=collisions_at(x,y)&i)) {
    if((i=collide_with(xx,VOIDLINK,x,y,c))&0x01) {
      if(i&0x8000) {
        if(subst_class) {
          m=subst_obj;
          v=destroy(VOIDLINK,m,5);
          if(v.t) return VOIDLINK;
          n=x_create(m,subst_class,x,y,d,CVALUE(c),NVALUE(im),NVALUE(0));
          if(n!=VOIDLINK) objects[m]->replacement=OVALUE(n);
          return n;
        } else {
          return subst_obj;
        }
      }
      return VOIDLINK;
    }
  }
  n=objalloc(c);
  if(n==VOIDLINK) Throw("Error creating object");
  o=objects[n];
  o->x=x;
  o->y=y;
  o->image=im;
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932















933
934
935
936
937
938
939
      }
    }
  }
  return v;
}

static int move_to(Uint32 from,Uint32 n,Uint32 x,Uint32 y) {
  Uint32 m;
  int i,xx,yy;
  Object*o;
  Object*p;
  Value v;
  if(n==VOIDLINK || (objects[n]->oflags&OF_DESTROYED) || n==control_obj) return 0;
  o=objects[n];
  if(lastimage_processing) Throw("Can't move during animation processing");
  if(x<1 || y<1 || x>pfwidth || y>pfheight) return 0;
  if(v_bool(send_message(from,n,MSG_MOVING,NVALUE(x),NVALUE(y),NVALUE(0)))) return 0;
  if(classes[o->class]->cflags&CF_PLAYER) {
    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,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|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];







|

















|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
      }
    }
  }
  return v;
}

static int move_to(Uint32 from,Uint32 n,Uint32 x,Uint32 y) {
  Uint32 k,m;
  int i,xx,yy;
  Object*o;
  Object*p;
  Value v;
  if(n==VOIDLINK || (objects[n]->oflags&OF_DESTROYED) || n==control_obj) return 0;
  o=objects[n];
  if(lastimage_processing) Throw("Can't move during animation processing");
  if(x<1 || y<1 || x>pfwidth || y>pfheight) return 0;
  if(v_bool(send_message(from,n,MSG_MOVING,NVALUE(x),NVALUE(y),NVALUE(0)))) return 0;
  if(classes[o->class]->cflags&CF_PLAYER) {
    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,n,x,y,o->class))&0x01) {
      if(i&0x8000) {
        m=subst_obj;
        v=destroy(n,m,5);
        if(v.t) return 0;
        k=x_create(m,subst_class,x,y,o->dir,CVALUE(o->class),NVALUE(o->image),OVALUE(n));
        if(k!=VOIDLINK) {
          objects[m]->replacement=objects[n]->replacement=OVALUE(k);
          destroy(m,n,6);
          o->distance+=abs(x-o->x)+abs(y-o->y);
          return 1;
        }
        return 0;
      }
      return i&0x04?1:0;
    }
  }
  pfunlink(n);
  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];

Modified heromesh.h from [3c737c4009] to [a48c2379a0].

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#define CVALUE(x) UVALUE(x,TY_CLASS)
#define MVALUE(x) UVALUE(x,TY_MESSAGE)
#define ZVALUE(x) UVALUE(x,TY_STRING)
#define OVALUE(x) ((x)==VOIDLINK?NVALUE(0):UVALUE(x,objects[x]->generation))
#define ValueTo64(v) (((sqlite3_int64)((v).u))|(((sqlite3_int64)((v).t))<<32))
#define ValueEq(x,y) ((x).t==(y).t && (x).u==(y).u)

#define N_MESSAGES 28
#define N_STANDARD_SOUNDS 49
extern const char*const standard_message_names[];
extern const char*const standard_sound_names[];
extern const char*const heromesh_key_names[256];

extern sqlite3*userdb;
extern xrm_db*resourcedb;







|







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#define CVALUE(x) UVALUE(x,TY_CLASS)
#define MVALUE(x) UVALUE(x,TY_MESSAGE)
#define ZVALUE(x) UVALUE(x,TY_STRING)
#define OVALUE(x) ((x)==VOIDLINK?NVALUE(0):UVALUE(x,objects[x]->generation))
#define ValueTo64(v) (((sqlite3_int64)((v).u))|(((sqlite3_int64)((v).t))<<32))
#define ValueEq(x,y) ((x).t==(y).t && (x).u==(y).u)

#define N_MESSAGES 29
#define N_STANDARD_SOUNDS 49
extern const char*const standard_message_names[];
extern const char*const standard_sound_names[];
extern const char*const heromesh_key_names[256];

extern sqlite3*userdb;
extern xrm_db*resourcedb;

Modified instruc.h from [ee33348f38] to [852aec28ef].

777
778
779
780
781
782
783

784
785
786
787
788
789
790
{"VolumeAt",8421602},
{"W",9437188},
{"WAHOO",8389399},
{"WHACK",8389422},
{"Walkable",8487139},
{"Weight",9142355},
{"WinLevel",8487140},

{"XDir",8487141},
{"XStep",8487142},
{"XYDir",8421607},
{"Xloc",8486983},
{"YDir",8487144},
{"YEEHAW",8389400},
{"YStep",8487145},







>







777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
{"VolumeAt",8421602},
{"W",9437188},
{"WAHOO",8389399},
{"WHACK",8389422},
{"Walkable",8487139},
{"Weight",9142355},
{"WinLevel",8487140},
{"XCREATE",8389148},
{"XDir",8487141},
{"XStep",8487142},
{"XYDir",8421607},
{"Xloc",8486983},
{"YDir",8487144},
{"YEEHAW",8389400},
{"YStep",8487145},
887
888
889
890
891
892
893
894
895
{"then",8683531},
{"tmark",8421611},
{"tuck",8421380},
{"uniq",8421618},
{"until",8683534},
{"while",8683535},
};
#define N_OP_NAMES 372
#endif







|

888
889
890
891
892
893
894
895
896
{"then",8683531},
{"tmark",8421611},
{"tuck",8421380},
{"uniq",8421618},
{"until",8683534},
{"while",8683535},
};
#define N_OP_NAMES 373
#endif

Modified names.h from [ada84b527b] to [256a5051e1].

23
24
25
26
27
28
29

30
31
32
33
34
35
36
#define MSG_COLLIDEBY 21
#define MSG_COLLIDE 22
#define MSG_COLLIDING 23
#define MSG_BLOCKED 24
#define MSG_CONNECT 25
#define MSG_NEXTWARP 26
#define MSG_CLICK 27

#ifdef HEROMESH_MAIN
const char*const standard_message_names[]={
 "INIT",
 "CREATE",
 "DESTROY",
 "BEGIN_TURN",
 "ARRIVED",







>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#define MSG_COLLIDEBY 21
#define MSG_COLLIDE 22
#define MSG_COLLIDING 23
#define MSG_BLOCKED 24
#define MSG_CONNECT 25
#define MSG_NEXTWARP 26
#define MSG_CLICK 27
#define MSG_XCREATE 28
#ifdef HEROMESH_MAIN
const char*const standard_message_names[]={
 "INIT",
 "CREATE",
 "DESTROY",
 "BEGIN_TURN",
 "ARRIVED",
53
54
55
56
57
58
59

60
61
62
63
64
65
66
 "COLLIDEBY",
 "COLLIDE",
 "COLLIDING",
 "BLOCKED",
 "CONNECT",
 "NEXTWARP",
 "CLICK",

};
const char*const standard_sound_names[]={
 "SPLASH",
 "POUR",
 "DOOR",
 "GLASS",
 "BANG",







>







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 "COLLIDEBY",
 "COLLIDE",
 "COLLIDING",
 "BLOCKED",
 "CONNECT",
 "NEXTWARP",
 "CLICK",
 "XCREATE",
};
const char*const standard_sound_names[]={
 "SPLASH",
 "POUR",
 "DOOR",
 "GLASS",
 "BANG",

Modified names.js from [3a1df8e65c] to [c748daa1b0].

28
29
30
31
32
33
34

35
36
37
38
39
40
41
 21 = COLLIDEBY
 22 = COLLIDE
 23 = COLLIDING
 24 = BLOCKED
 25 = CONNECT
 26 = NEXTWARP
 27 = CLICK

`.split("\n").map(x=>/^ *([0-9]+) = ([^ ]*) *$/.exec(x)).filter(x=>x);
const standard_sound_names=[];
`
 SPLASH
 POUR
 DOOR
 GLASS







>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 21 = COLLIDEBY
 22 = COLLIDE
 23 = COLLIDING
 24 = BLOCKED
 25 = CONNECT
 26 = NEXTWARP
 27 = CLICK
 28 = XCREATE
`.split("\n").map(x=>/^ *([0-9]+) = ([^ ]*) *$/.exec(x)).filter(x=>x);
const standard_sound_names=[];
`
 SPLASH
 POUR
 DOOR
 GLASS