another one IVAN fork

Yesterday, 10:16 pm
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 169
sadly, there is no wizard command to show dangerous squares. basically, the algo stops when:
1. there is some danger around.
2. it is about to step on a dangerous square.
3. there is something interesting around (new items, new closed doors).
4. there is new direction to go (actually, when the number of available directions changed).

rule #4 allows to walk both in 1-tile tunnels and in wide hallways. and there are some heuristics to detect narrow turns and follow them.

the algo has little flaws here and there, but most of the time it should work as expected. tbh, i am not happy with that mess of a code, but… it works.
Yesterday, 10:28 pm
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 169
as for Goblin Fortress problem… i cannot see how vanilla manages to NOT segfault from time to time on it. `RoomDefault` for level says: `Size = 3:7,3:7;`. Living Quarters is `RandomLevel 0:3;`, where that room size is in effect. it has `Square, Random HAS_NO_OTERRAIN; { OTerrain = decoration(CHEAP_BED); Times = 2:6; }`. this simply doomed to generate more items than there is free space.

now, in `level::MakeRoom()` the last part of the code applies room script. it starts with `for(const squarescript& Script : RoomScript->GetSquare())` line. there is the code to get random position in a room, it calls `level::GetRandomSquare()`, and that call returns `ERROR_V2` when there is no room `ERROR_V2` is defined as `(-0x8000, -0x8000);`

in k8ivan the code is:
  const std::list<squarescript> Square = RoomScript->GetSquare();
  for (std::list<squarescript>::const_iterator i = Square.begin(); i != Square.end(); ++i) {
    game::BusyAnimation();
    const squarescript *Script = &*i;
    const interval *ScriptTimes = Script->GetTimes();
    const int Times = (ScriptTimes ? ScriptTimes->Randomize() : 1);
    for (int t = 0; t < Times; ++t) {
      v2 SquarePos;
      if (Script->GetPosition()->GetRandom()) {
        const rect *ScriptBorders = Script->GetPosition()->GetBorders();
        rect Borders = ScriptBorders ? *ScriptBorders+Pos : rect(Pos, Pos+Size-v2(1, 1));
        SquarePos = GetRandomSquare(0, Script->GetPosition()->GetFlags(), &Borders);
      } else {
        SquarePos = Pos+Script->GetPosition()->GetVector();
      }
      if (SquarePos == ERROR_V2) {
        ABORT("KABOOM!");
      } else {
        Map[SquarePos.X][SquarePos.Y]->ApplyScript(Script, RoomClass);
      }
    }
  }

and in vanilla the code is:
  for(const squarescript& Script : RoomScript->GetSquare())
  {
    game::BusyAnimation();
    const interval* ScriptTimes = Script.GetTimes();
    int Times = ScriptTimes ? ScriptTimes->Randomize() : 1;

    for(int t = 0; t < Times; ++t)
    {
      v2 SquarePos;

      while(true)
      {
        if(Script.GetPosition()->GetRandom())
        {
          const rect* ScriptBorders = Script.GetPosition()->GetBorders();
          rect Borders = ScriptBorders ? *ScriptBorders + Pos : rect(Pos, Pos + Size - v2(1, 1));
          SquarePos = GetRandomSquare(0, Script.GetPosition()->GetFlags(), &Borders);
        }
        else
          SquarePos = Pos + Script.GetPosition()->GetVector();

        Map[SquarePos.X][SquarePos.Y]->ApplyScript(&Script, RoomClass);

        if(CheckExpansiveArea(GetLSquare(SquarePos)->GetOLTerrain(), SquarePos.X, SquarePos.Y, !Script.GetPosition()->GetRandom()))
          break;
      }
    }
  }
oops. no checks. that's why k8ivan crashed — it properly detects erorr. and vanilla seems to ignore it, either going haywire shooting random memory, or segfaulting. so i wonder WHY doesn't vanilla segfaulting quite often on GF generation?

i mean, `Map` indexing is not bounds-checked in any way, it is just `lsquare*** Map` — not a fancy class, just a pointer. so the code is doomed to access random out-of-bounds memory two times (first index, second index), and then pass that gibberish to `ApplyScript()` as `this` pointer.
Today, 2:37 am
Joined: Apr 2, 2014
Occupation: Navastating
Location: Aslona
Posts: 790
That's a good question and a good find.
Today, 6:05 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 169
packed all game data into one big wad file. of course, it is still possible to load everything from raw disk files for development, but the main game now consists of .exe and .vwad only. the game even knows if it is a "genuine" vwad created by me, or not (it is digitally signed). it doesn't matter, and the game does nothing with this knowledge, but it knows.

i'm not going to prevent modifications of course (and how would i, the sources are open), it just happened that my vwad library has this feature. it is just to make binary distributions easier. i am also planning to use this system for user mods in the (distant) future.
Today, 6:55 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 169
hm. i always wondered why can't i toss an armed mine out of myself. or a bear trap, for that matter. implemented it. now you can arm a trap, and then throw it away. it has a fun effect with mines: they explode if they hit something. yay, finally i have a use for them!

hitting someone with armed bear trap does nothing interesting, tho: it simply deactivates. the same happens if it hits a wall (naturally .

so you can either put the traps down as before, or throw away and hope it works. now go hunting for unarmed mines, they are of great use!

i still want a way to disarm a mine too, but cannot think out how to do it. not with the code, but gameplay-wise. maybe it should be a separate action, depending on Agi and Int? so skilled characters could disarm traps in more intelligent way than just kicking them. high-Int monsters prolly should be able to do that too — so no more cheap kills on Petrus with a pile of armed mines. (he has Searching, if i remember right?)
Jump to