Free Hero Mesh

Check-in [a5ad5e4eeb]
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:Many changes (still not quite right, it seems)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a5ad5e4eeb7f7ce8861e7d17074b589e49837aa7
User & Date: user on 2020-12-18 08:07:32
Other Links: manifest | tags
Context
2020-12-18
08:13
According to a test I have made, MoveTo() should clear OF_DONE if successful, even though this is not documented check-in: c8abf002f2 user: user tags: trunk
08:07
Many changes (still not quite right, it seems) check-in: a5ad5e4eeb user: user tags: trunk
02:00
Correct the implementation of sink() so that the objects above and below the ones being switched are linked correctly; also, objtrash() does not need to reset the up/down links check-in: 3aa2e5e3bd user: user tags: trunk
Changes

Modified exec.c from [4dabc08567] to [4fb502d2cb].

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
  if(o->weight>o->inertia) goto fail;
  o->inertia-=o->weight;
  restart:
  if(hit&0x100000) dir=o->dir;
  objF=obj_dir(obj,dir);
  if(objF==VOIDLINK) goto fail;
  oF=objects[objF];
  hF=height_at(oF->x,oF->y);
  if(dir&1) {
    // Diagonal movement
    objLF=obj_dir(obj,(dir+1)&7);
    objRF=obj_dir(obj,(dir-1)&7);
    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) {
        oE=objects[objE];
        if(oE->height>0 && !(oE->oflags&(OF_VISUALONLY|OF_DESTROYED))) {
          v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(hit|0x80000));
          if(v.t) Throw("Type mismatch in HIT/HITBY");
          hit=v.u&(classes[o->class]->cflags&CF_COMPATIBLE?0xFC098F7F:-1);
          if(hit&8) goto fail;
          if(!(hit&0x11)) {
            v=send_message(obj,objE,MSG_HITBY,NVALUE(o->x),NVALUE(o->y),NVALUE(hit|0x80000));
            if(v.t) Throw("Type mismatch in HIT/HITBY");
            hit=v.u&(classes[oE->class]->cflags&CF_COMPATIBLE?0xFC098F7F:-1);
            if(hit&8) goto fail;
          }
        }
        objE=obj_below(objE);
      }
      if(!(hit&0x402008)) {
        if(hF<=o->climb || (hit&0x200000)) {
          if(hit&0x20000) goto success;

          if(move_to(from,obj,oF->x,oF->y)) goto success; else goto fail;
        }
      }
    } else {
      // Volume is too much; hit the objects it won't go between
      objE=objLF;
      while(objE!=VOIDLINK) {
        oE=objects[objE];
        if(oE->height>0 && !(oE->oflags&(OF_VISUALONLY|OF_DESTROYED))) {
          v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(0x80008));
          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|0x80008));
        }
        objE=obj_below(objE);
      }
      objE=objRF;
      while(objE!=VOIDLINK) {
        oE=objects[objE];
        if(oE->height>0 && !(oE->oflags&(OF_VISUALONLY|OF_DESTROYED))) {
          v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(0x80008));
          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|0x80008));
        }
        objE=obj_below(objE);
      }
    }
  } else {
    // Orthogonal movement
    if(hit) hit=(hit&0x0C000000)|0x800;
    objE=objF;
    while(objE!=VOIDLINK) {
      oE=objects[objE];
      if(oE->height>0 && !(oE->oflags&(OF_VISUALONLY|OF_DESTROYED))) {
        hit&=~7;
        // HIT/HITBY messages
        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?0xFC098F7F:-1);
        if(hit&8) goto fail;
        if(!(hit&0x11)) {







|











|
















>








|









|













|







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
  if(o->weight>o->inertia) goto fail;
  o->inertia-=o->weight;
  restart:
  if(hit&0x100000) dir=o->dir;
  objF=obj_dir(obj,dir);
  if(objF==VOIDLINK) goto fail;
  oF=objects[objF];
  hF=oF?height_at(oF->x,oF->y):0;
  if(dir&1) {
    // Diagonal movement
    objLF=obj_dir(obj,(dir+1)&7);
    objRF=obj_dir(obj,(dir-1)&7);
    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) {
        oE=objects[objE];
        if(oE->height>0) {
          v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(hit|0x80000));
          if(v.t) Throw("Type mismatch in HIT/HITBY");
          hit=v.u&(classes[o->class]->cflags&CF_COMPATIBLE?0xFC098F7F:-1);
          if(hit&8) goto fail;
          if(!(hit&0x11)) {
            v=send_message(obj,objE,MSG_HITBY,NVALUE(o->x),NVALUE(o->y),NVALUE(hit|0x80000));
            if(v.t) Throw("Type mismatch in HIT/HITBY");
            hit=v.u&(classes[oE->class]->cflags&CF_COMPATIBLE?0xFC098F7F:-1);
            if(hit&8) goto fail;
          }
        }
        objE=obj_below(objE);
      }
      if(!(hit&0x402008)) {
        if(hF<=o->climb || (hit&0x200000)) {
          if(hit&0x20000) goto success;
          if(!oF) goto fail;
          if(move_to(from,obj,oF->x,oF->y)) goto success; else goto fail;
        }
      }
    } else {
      // Volume is too much; hit the objects it won't go between
      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(0x80008));
          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|0x80008));
        }
        objE=obj_below(objE);
      }
      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(0x80008));
          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|0x80008));
        }
        objE=obj_below(objE);
      }
    }
  } else {
    // Orthogonal movement
    if(hit) hit=(hit&0x0C000000)|0x800;
    objE=objF;
    while(objE!=VOIDLINK) {
      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));
        if(v.t) Throw("Type mismatch in HIT/HITBY");
        hit|=v.u&(classes[o->class]->cflags&CF_COMPATIBLE?0xFC098F7F:-1);
        if(hit&8) goto fail;
        if(!(hit&0x11)) {
783
784
785
786
787
788
789

790
791
792
793
794
795
796
      objE=obj_below(objE);
    }
    if(hit&0x2008) goto fail;
    if((hit&0x48000)==0x8000) goto restart;
    if(!(hit&0x400000)) {
      if(hF<=o->climb || (hit&0x200000)) {
        if(hit&0x20000) goto success;

        if(move_to(from,obj,oF->x,oF->y)) goto success; else goto fail;
      }
    }
    // Sliding
    if(hit&0x80) goto fail;
    hit|=0x10000;
    







>







784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
      objE=obj_below(objE);
    }
    if(hit&0x2008) goto fail;
    if((hit&0x48000)==0x8000) goto restart;
    if(!(hit&0x400000)) {
      if(hF<=o->climb || (hit&0x200000)) {
        if(hit&0x20000) goto success;
        if(!oF) goto fail;
        if(move_to(from,obj,oF->x,oF->y)) goto success; else goto fail;
      }
    }
    // Sliding
    if(hit&0x80) goto fail;
    hit|=0x10000;
    
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523




1524
1525
1526
1527
1528
1529
1530
  }
  nobjects=0;
  free(objects);
  objects=0;
  gameover=0;
}

static Uint8 execute_animation(Uint8 clock,Uint32 obj) {
  Object*o=objects[obj];
  Animation*a=o->anim;
  if(!(a->step[a->lstep].flag&ANI_ONCE)) return clock;
  if(a->ltime>=a->step[a->lstep].speed) {
    a->ltime=0;
    if(o->image==a->step[a->lstep].end) {
      a->status&=~ANISTAT_LOGICAL;
      if(classes[o->class]->cflags&CF_COMPATIBLE) lastimage_processing=1;
      send_message(VOIDLINK,obj,MSG_LASTIMAGE,NVALUE(0),NVALUE(0),NVALUE(0));
      lastimage_processing=0;
    } else {
      if(a->step[a->lstep].start>a->step[a->lstep].end) --o->image; else ++o->image;
    }
  }
  if(!(a->status&ANISTAT_LOGICAL) || !(a->step[a->lstep].flag&ANI_ONCE)) return clock;
  if(clock>a->step[a->lstep].speed-a->ltime) return a->step[a->lstep].speed-a->ltime;
  return clock;
}

const char*execute_turn(int key) {
  Uint8 busy,clock;
  Uint32 m,n,turn;
  Object*o;
  Value v;
  int i;
  if(!key) return 0;




  if(setjmp(my_env)) return my_error;
  if(quiz_text) {
    sqlite3_free(quiz_text);
    quiz_text=0;
    if(key_ignored) {
      if(quiz_obj.t) quiz_obj=NVALUE(0); else return 0;
    } else if(!quiz_obj.t) {







|


|











<
<
<








|
>
>
>
>







1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513



1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
  }
  nobjects=0;
  free(objects);
  objects=0;
  gameover=0;
}

static void execute_animation(Uint32 obj) {
  Object*o=objects[obj];
  Animation*a=o->anim;
  if(!(a->step[a->lstep].flag&ANI_ONCE)) return;
  if(a->ltime>=a->step[a->lstep].speed) {
    a->ltime=0;
    if(o->image==a->step[a->lstep].end) {
      a->status&=~ANISTAT_LOGICAL;
      if(classes[o->class]->cflags&CF_COMPATIBLE) lastimage_processing=1;
      send_message(VOIDLINK,obj,MSG_LASTIMAGE,NVALUE(0),NVALUE(0),NVALUE(0));
      lastimage_processing=0;
    } else {
      if(a->step[a->lstep].start>a->step[a->lstep].end) --o->image; else ++o->image;
    }
  }



}

const char*execute_turn(int key) {
  Uint8 busy,clock;
  Uint32 m,n,turn;
  Object*o;
  Value v;
  int i;
  if(!key) {
    // This is part of initialization; if anything triggered, it must be executed now
    all_flushed=1;
    goto trig;
  }
  if(setjmp(my_env)) return my_error;
  if(quiz_text) {
    sqlite3_free(quiz_text);
    quiz_text=0;
    if(key_ignored) {
      if(quiz_obj.t) quiz_obj=NVALUE(0); else return 0;
    } else if(!quiz_obj.t) {
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638







1639



1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
          busy=1;
        }
        if(o->arrived) {
          send_message(VOIDLINK,n,MSG_ARRIVED,NVALUE(0),NVALUE(0),NVALUE(turn));
          o->arrived=0;
          busy=1;
        }
        if(o->anim && (o->anim->status&ANISTAT_LOGICAL)) clock=execute_animation(clock,n);
        if(o->oflags&(OF_BUSY|OF_USERSIGNAL)) busy=1;
      } else {
        o->departed2=o->departed;
        o->departed=0;
        o->arrived2=o->arrived;
        o->arrived=0;
        if(o->oflags&OF_MOVED) o->oflags=(o->oflags|OF_MOVED2)&~OF_MOVED;
      }
      n=m;
    }
  }
  n=lastobj;
  while(n!=VOIDLINK) {
    o=objects[n];
    if(!(classes[o->class]->cflags&CF_COMPATIBLE)) {
      if(o->oflags&OF_MOVED2) send_message(VOIDLINK,n,MSG_MOVED,NVALUE(0),NVALUE(0),NVALUE(turn)),busy=1;
      if(o->departed2) send_message(VOIDLINK,n,MSG_DEPARTED,NVALUE(o->departed2),NVALUE(0),NVALUE(turn)),busy=1;
      if(o->arrived2) send_message(VOIDLINK,n,MSG_ARRIVED,NVALUE(o->arrived2),NVALUE(0),NVALUE(turn)),busy=1;
      o->oflags&=~OF_MOVED2;
      o->arrived2=o->departed2=0;
      if(o->anim && (o->anim->status&ANISTAT_LOGICAL)) clock=execute_animation(clock,n);
      if(o->oflags&(OF_BUSY|OF_USERSIGNAL)) busy=1;
    }
    n=o->prev;
  }
  // Ending phase
  if(!busy && !all_flushed) {
    n=lastobj;
    while(n!=VOIDLINK) {
      v=send_message(VOIDLINK,n,MSG_END_TURN,NVALUE(turn),NVALUE(0),NVALUE(0));
      if(v_bool(v) || objects[n]->arrived || objects[n]->departed) busy=1;
      if(objects[n]->oflags&(OF_BUSY|OF_USERSIGNAL|OF_MOVED)) busy=1;
      n=objects[n]->prev;
    }
    turn++;
    if(!busy) all_flushed=1;
  }
  // Clock phase







  if(!clock) clock=1;



  n=lastobj;
  while(n!=VOIDLINK) {
    o=objects[n];
    if(o->oflags&(OF_BUSY|OF_USERSIGNAL|OF_MOVED)) busy=1;
    if(o->arrived || o->departed) busy=1;
    if(o->anim && (o->anim->status&ANISTAT_LOGICAL)) {
      if(o->anim->step[o->anim->lstep].flag&ANI_ONCE) {
        i=o->anim->ltime+clock;
        o->anim->ltime=i>255?255:i;
        busy=1;
      }
    }
    n=o->prev;
  }
  if(busy) goto trig;
  // Cleanup phase
  for(n=0;n<nobjects;n++) if(objects[n] && (objects[n]->oflags&OF_DESTROYED)) objtrash(n);
  if(generation_number<=TY_MAXTYPE) return "Too many generations of objects";







|




















|

















>
>
>
>
>
>
>
|
>
>
>





|
<
|
|
|
<







1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658

1659
1660
1661

1662
1663
1664
1665
1666
1667
1668
          busy=1;
        }
        if(o->arrived) {
          send_message(VOIDLINK,n,MSG_ARRIVED,NVALUE(0),NVALUE(0),NVALUE(turn));
          o->arrived=0;
          busy=1;
        }
        if(o->anim && (o->anim->status&ANISTAT_LOGICAL)) execute_animation(n);
        if(o->oflags&(OF_BUSY|OF_USERSIGNAL)) busy=1;
      } else {
        o->departed2=o->departed;
        o->departed=0;
        o->arrived2=o->arrived;
        o->arrived=0;
        if(o->oflags&OF_MOVED) o->oflags=(o->oflags|OF_MOVED2)&~OF_MOVED;
      }
      n=m;
    }
  }
  n=lastobj;
  while(n!=VOIDLINK) {
    o=objects[n];
    if(!(classes[o->class]->cflags&CF_COMPATIBLE)) {
      if(o->oflags&OF_MOVED2) send_message(VOIDLINK,n,MSG_MOVED,NVALUE(0),NVALUE(0),NVALUE(turn)),busy=1;
      if(o->departed2) send_message(VOIDLINK,n,MSG_DEPARTED,NVALUE(o->departed2),NVALUE(0),NVALUE(turn)),busy=1;
      if(o->arrived2) send_message(VOIDLINK,n,MSG_ARRIVED,NVALUE(o->arrived2),NVALUE(0),NVALUE(turn)),busy=1;
      o->oflags&=~OF_MOVED2;
      o->arrived2=o->departed2=0;
      if(o->anim && (o->anim->status&ANISTAT_LOGICAL)) execute_animation(n);
      if(o->oflags&(OF_BUSY|OF_USERSIGNAL)) busy=1;
    }
    n=o->prev;
  }
  // Ending phase
  if(!busy && !all_flushed) {
    n=lastobj;
    while(n!=VOIDLINK) {
      v=send_message(VOIDLINK,n,MSG_END_TURN,NVALUE(turn),NVALUE(0),NVALUE(0));
      if(v_bool(v) || objects[n]->arrived || objects[n]->departed) busy=1;
      if(objects[n]->oflags&(OF_BUSY|OF_USERSIGNAL|OF_MOVED)) busy=1;
      n=objects[n]->prev;
    }
    turn++;
    if(!busy) all_flushed=1;
  }
  // Clock phase
  n=lastobj;
  while(n!=VOIDLINK) {
    o=objects[n];
    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)) busy=1;
    if(o->arrived || o->departed) busy=1;
    if(o->anim && (o->anim->status&ANISTAT_LOGICAL) && (o->anim->step[o->anim->lstep].flag&ANI_ONCE)) {

      i=o->anim->ltime+clock;
      o->anim->ltime=i>255?255:i;
      busy=1;

    }
    n=o->prev;
  }
  if(busy) goto trig;
  // Cleanup phase
  for(n=0;n<nobjects;n++) if(objects[n] && (objects[n]->oflags&OF_DESTROYED)) objtrash(n);
  if(generation_number<=TY_MAXTYPE) return "Too many generations of objects";
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
  all_flushed=0;
  lastimage_processing=0;
  vstackptr=0;
  move_number=0;
  current_key=0;
  broadcast(VOIDLINK,0,MSG_INIT,NVALUE(0),NVALUE(0),NVALUE(0),0);
  broadcast(VOIDLINK,0,MSG_POSTINIT,NVALUE(0),NVALUE(0),NVALUE(0),0);
  if(generation_number<=TY_MAXTYPE) return "Too many generations of objects";
  return 0;
}







|
|

1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
  all_flushed=0;
  lastimage_processing=0;
  vstackptr=0;
  move_number=0;
  current_key=0;
  broadcast(VOIDLINK,0,MSG_INIT,NVALUE(0),NVALUE(0),NVALUE(0),0);
  broadcast(VOIDLINK,0,MSG_POSTINIT,NVALUE(0),NVALUE(0),NVALUE(0),0);
  if(gameover) return 0;
  return execute_turn(0);
}

Modified game.c from [4ed4013de1] to [8fca8ad497].

489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
        if(i==-2) {
          main_options['e']=1;
          SDL_SetTimer(0,0);
          return;
        }
        if(inputs_count) {
          //TODO: Check for solution replay
          for(i=0;i<inputs_count && !gameover;i++) input_move(inputs[i]);
          inputs_count=0;
        }
        redraw_game();
        timerflag=0; // ensure we have not missed a timer event
        break;
    }
  }







|







489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
        if(i==-2) {
          main_options['e']=1;
          SDL_SetTimer(0,0);
          return;
        }
        if(inputs_count) {
          //TODO: Check for solution replay
          for(i=0;i<inputs_count && !gameover;i++) if(inputs[i]) input_move(inputs[i]);
          inputs_count=0;
        }
        redraw_game();
        timerflag=0; // ensure we have not missed a timer event
        break;
    }
  }