another one IVAN fork

Yesterday, 10:16 pm
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 171
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: 171
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: 791
That's a good question and a good find.
Today, 6:05 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 171
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: 171
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?)
Today, 8:19 am
Joined: Apr 2, 2014
Occupation: Navastating
Location: Aslona
Posts: 791
vasiliy wrote
hitting someone with armed bear trap does nothing interesting, tho: it simply deactivates. the same happens if it hits a wall (naturally .

They should attempt to trap an arm of a humanoid enemy they hit.

vasiliy wrote
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.

In vanilla, you have a Dex-based chance to disarm a mine if you levitate above it.

Whatever way you choose to implement it, I think it should be based on Dex (and possibly Int). Agility in IVAN is tied to legs (dodging, running), Dexterity is for arms (weapon accuracy).
Today, 8:21 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 171
as i usually find it hard to track my satiation state, i added two more status indicators: "almost hungry" and "almost satiated". after all, you can more-or-less feel how full your stomach is! they say that it is good for your health to be almost, but not quite satiated!

"almost hungry" is when you are ~25-30 percent above "hungry" status, and "almost satiated" is ~20-25 percent before "satiated". it is not exact, and gives you a rough estimate.
Today, 8:26 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 171
red_kangaroo wrote
They should attempt to trap an arm of a humanoid enemy they hit.
actually, that's what original devs wrote. i only added throwing, and the game did the rest. while it wasn't possible to throw armed traps, the code does handle it. i thought that bear traps will trap monsters, but no. maybe i'll fix that later.


red_kangaroo wrote
In vanilla, you have a Dex-based chance to disarm a mine if you levitate above it.

Whatever way you choose to implement it, I think it should be based on Dex (and possibly Int). Agility in IVAN is tied to legs (dodging, running), Dexterity is for arms (weapon accuracy).
yeah, i meant Dexterity, not Agility, of course. dunno how i got it wrong… prolly my Int is too low. but shouldn't science posting on this forum give Int boost?
Jump to