another one IVAN fork

Jan 21, 10:16 pm
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
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.
Jan 21, 10:28 pm
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
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.
Jan 22, 2:37 am
Joined: Apr 2, 2014
Occupation: Navastating
Location: Aslona
Posts: 807
That's a good question and a good find.
Jan 22, 6:05 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
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.
Jan 22, 6:55 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
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?)
Jan 22, 8:19 am
Joined: Apr 2, 2014
Occupation: Navastating
Location: Aslona
Posts: 807
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).
Jan 22, 8:21 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
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.
Jan 22, 8:26 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
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?
Jan 23, 12:43 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
couldn't sleep properly (irl , and thought: maybe carnivorous plants should eat bodies in adjacent squares too? it doesn't matter much in gameplay sense, but looks more interesting, i believe. often players don't even know that those plants are not simply named "carnivorous".

in case somebody wonder why i'm pushing so much code and ideas… it is horn of plenty… er… i haven't played IVAN for several years (simply had no time), and now i am looking on it with a fresh pair of eyes. and i started noticing quirks i took for granted and got used to. so i am trying to implement as much as possible before running out of steam again.

p.s.: i believe the new test build is on its way. also, is there any way to manage attachments on the forum?
Jan 23, 1:04 am
Joined: Sep 3, 2024
Occupation: Childcare Provider
Location: Victoria, British Columbia
Interests: Retro gaming, retro computers, TTRPGS, painting and crafting miniatures and terrain, wargames
Posts: 24
vasiliy wrote
it's really strange, i've never seen it happens. the save format is already incompatible (sigh), but would you please attach a screenshot of the game when it happens? maybe i'll be able to spot something.

I can do you one better, here's a video showing my problem: https://youtu.be/rkkacteatRM

I have cleared the level enough to know that there's nothing dangerous nearby and there's nothing on the floor and I do it in two different places. This happens on every save.
Jan 23, 3:33 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
thank you! it's really, really strange indeed. it sure doesn't look like there is something blocking there.

i am working on the new build, and then you'll be able to send me a save. i will delay breaking changes for some time to be able to analyze it. i really don't have a slightest idea, and need to look at the loaded game.

the problem with saves is that they're breaking even on small script changes. i ought to tag the build in version control so i could checkout it, but i forgot. sorry. i'll try to tag it this time.
Jan 23, 6:30 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
fun thing: Kaethos is in his own team (tourist guide). so it is possible to slay whole New Attnam, and still have him friendly, and asking to plant the seedling to free… various lumps of flesh lying around, i guess.
Jan 23, 10:58 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
saved games are stored in single archive file now. coincidentally, it is the same vwad format which is used for game data. because my library supports creating it, and it is compressed (and the compression is even slightly better than with zip archives; nothing to be proud of, tho).

this is not only handy for savescumming (and don't tell me you've never done that! , but also allows atomic save updates. i.e. the old save will be replaced by the new one only if saving succeeded, and this operation is atomic. this should cause much less broken saves from various game crashes.
Jan 23, 11:58 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
btw. as we have cleavers now, shouldn't they be used to butcher corpses to lumps of flesh? so we could can those lumps.
Jan 24, 5:13 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
i am really tired of counting materials. i bet all other script writers too. so i implemented new syntax for material configs:
instead of:
    MainMaterialConfig := { COPPER, BRONZE, IRON, STEEL, METEORIC_STEEL,
                            MITHRIL, OCTIRON, LEAD, ALUMINIUM, NICKEL,
                            CHROME, STAINLESS_STEEL; }
    MaterialConfigChances := { 25, 150, 50, 10, 5, 1, 1, 150, 75, 25, 1, 5; }

you can use:
    MainMaterialConfigExt := { COPPER:25, BRONZE:150, IRON:50, STEEL:10, METEORIC_STEEL:5,
                              MITHRIL:1, OCTIRON:1, LEAD:150, ALUMINIUM:75, NICKEL:25,
                              CHROME:1, STAINLESS_STEEL:5; }
much better, isn't it?

this is ugly hack in parser, not new database property. but hey, it works.
Jan 24, 4:41 pm
Joined: Sep 8, 2010
Occupation: Petty Functionary
Location: Drinking pea soup in the world map
Interests: Mangoes
Posts: 1,217
I'm very happy to see this fork back in active development, I've been a long admirer of your codebase and the innovations taking shape are exciting.

Have you got any tips for building it on linux?
Batman? wrote
its been so long since i had gotten that far i didnt think it through. arrrr!!!!!!
Jan 24, 9:58 pm
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
fejoa wrote
I'm very happy to see this fork back in active development, I've been a long admirer of your codebase and the innovations taking shape are exciting.
thank you!

fejoa wrote
Have you got any tips for building it on linux?
basically, you need k8jam, and it should do the rest. k8jam has no external dependencies, and should be buildable with provided shell script, producing single standalone binary. it need not to be installed.

then "k8jam config --help" will show configure options. but i'm not sure if all of them work. i believe that "k8jam config" should work, tho. then "k8jam" again to build the binary. do not try to install it, this is not supported yet. just run from where it built.

please, note that 64-bit builds are not supported, so you will need 32-bit support installed. k8jam should automatically add "-m32" flags on 64-bit system (i hope . also, SDL2, SDL2 Mixer, zlib, libpng 1.6, and working OpenGL libs. k8jam will detect them and complain. also, i believe that ALSA is required for sound, due to one callback in the source; it can be disabled, tho; everyhting it does is silences ALSA "pcm buffer underrun" errors. i'll add libalsa detection to configure later.

i believe that's it. everything should be fairly starightforward.
Jan 24, 11:00 pm
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
by the way, worldmap! i rewrote POI placement several times already, and will rewrite it at least one more time, but there are some interesting things in there already:
  // special POI
  Config ATTNAM;
  {
    NameSingular = "Attnam";
    BitmapPos = 0, 48;
    NameStem = "mighty cathedral reaching the clouds";
    UsesLongArticle = false;
    AttachedDungeon = ATTNAM;
    CanBeGenerated = true;
    NativeGTerrainType := { LEAFY_FOREST, EVERGREEN_FOREST, STEPPE }
    WantContinentWith = ATTNAM; // yeah, sorry
    RevealEnvironmentInitially = true;
    // UT exit is generated *BEFORE* Attnam, this is how the game works!
    DistancePOI = UNDER_WATER_TUNNEL_EXIT;
    MinimumDistanceTo = 3;
    MaximumDistanceTo = 6;
    MinimumContinentSize = 25;
    MaximumContinentSize = 700; // it was 1000 before, but i want smaller continents
  }
here, you can see some new properties. `WantContinentWith` (for Attnam it is a hack, though, because Attnam actually placed *after* UT Exit). `*ContinentSize` fields moved out of source code. `DistancePOI` and distance props are there to enusre that you don't have to travel half of the continent to find Attnam. there is nothing interesting in overworld as of yet, so there is no reason to spread POIs. most POIs are more-or-less close now.

  Config ASLONA_CASTLE;
  {
    Probability = 100;
    CanBeSkipped = false;
    NameSingular = "Aslona Castle";
    BitmapPos = 96, 128;
    NameStem = "mighty seaside castle";
    UsesLongArticle = false;
    AttachedDungeon = ASLONA_CASTLE;
    CanBeGenerated = true;
    NativeGTerrainType := { STEPPE, LEAFY_FOREST }
    SeparateContinent = true;
    CloseTo = ATTNAM; // try to move as close as possible to Attnam
    //RevealEnvironmentInitially = true; //for debug
    MinimumContinentSize = 25;
    MaximumContinentSize = 0; // any size
  }

  Config REBEL_CAMP;
  {
    Probability = 100;
    CanBeSkipped = false;
    BitmapPos = 16, 64;
    NameSingular = "Rebel Camp";
    NameStem = "hidden camp";
    UsesLongArticle = false;
    AttachedDungeon = REBEL_CAMP;
    CanBeGenerated = true;
    NativeGTerrainType := { JUNGLE, STEPPE, LEAFY_FOREST, EVERGREEN_FOREST }
    WantContinentWith = ASLONA_CASTLE;
    //RevealEnvironmentInitially = true; //for debug
    DistancePOI = ASLONA_CASTLE;
    MinimumDistanceTo = 5;
    MaximumDistanceTo = 9;
  }
now, some more interesting things. `SeparateContinent = true;` — this does exactly what it says on the tin. Aslona will be placed on a separate continent. then `WantContinentWith = ASLONA_CASTLE;` in Rebel Camp will ensure that Rebels will not travel too far away. `CloseTo = ATTNAM;` — this will try to find the point close to Attnam (but still on another continent), so you won't be forced to sail over the whole world.

the additions are not fully working yet (POI placement algo sux), but even in half-working state they make the overwold more manageable.

now we prolly need an overworld compass too: Aslona still might be quite away, and it is sometimes to hard to find it on a worldmap, and then even harder to keep the direction to it. maybe even "autotravel" command, so the ship will automatically sail to Aslona and back.


the problem with current POI placement code is that it only tries once with random coords, and if it fails, it throws away the whole world, starting from scratch. it doesn't have to be this way: we might still find suitable POI placements if we'll try hard enough. this is kind of graph searching problem, which i tried to solve with brute force first. and you might guess how well it goes — solving graph problems exploring all possibilities, without any heuristics to cut off dead ends. that is, it never finishes even once.

i have to rewrite the code, aggressively pruning impossible solutions. this way it should work MUCH faster, and satisfy all constraints in no time. at least i believe so. for the time being, the old algo is still used.


p.s.: and completely unrelated note: the game shows "saving…" popup when saving the game. it might take some time now due to all compression and such (less than half of a second, but still noticeable), so the popup will tell you that the game is busy archiving your precious character and dungeons, not stuck in some endless loop.
Jan 24, 11:50 pm
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
also, saved game selector now has not only in-game screenshot, but some game description too. this description is just a .txt file inside saved game archive, so i can add various things there without touching savegame selector.
Jan 25, 1:00 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
also, another feature i always wanted to implement: automatic registration and verification of material and config names.

there is no reason to manually list all materials and possible configs, the game could infer them on its own. k8ivan already using constants from "define.dat" instead of hardcoded C++ defines, so it would be the next logical step. there is no reason why the game could not generate the numbers itself instead of using hand-made enumerations. we will need to save config and material names instead of numbers to saves, but this is something which is actually *better* for savegame compatibility.

most of the foundation code to implement this is already in there, i only need to do final 20% of work (which takes 80% of time, of course .
Jan 25, 5:57 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
brute-force POI placement code now culling most impossible positions. it still might fail to find a solution, and even if the solution is found, it is not as perfect as i want it to be. but i like the result more than the old version, so i'll prolly keep brute force approach. the downside is that BF might take a long time on some worlds, so i abort searching after ~10 seconds, and restart with the fresh new world. most of the time generation takes less than a second, though. i'll let is pass for now.

also, added "feeling messages" to POIs which might be generated with some probability. Alien Vessel dungeon, for example, is not only completely optional (and have no quest attached), but it has only 60% probability of being generated. the game should somehow tell the player that there is something interesting to look for besides quest dungeons, so if Alien Vessel is generated, the game will show its "feeling message". A.V. may be generated quite far from other places, so it is fair to tell players if they should go explore the continent or not.
Jan 25, 8:19 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
by the way: is it possible to kill the stupid kid (or wait for him to be killed), carry his body to the exit, and resurrect him? escort missions sux, especially with this dumb m… mighty future king!

i remember reading about a bug which prevents finishing the quest this way somewhere on the forum. have to check the source code, i guess.
Jan 25, 11:37 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
long and unineresting gameplay story
SPOILER ALERT. Click here to see text.
it is fun how balanced spawn makes the game look smart. i just started new session, and my character was born with really shitty stats. in addition to it, i found no boots, no gauntlets, no good weapon, nor even a helmet in UT. colleted enough bottles to chop Jenny with a mithril spear, though. got to GC, and the game suddenly noticed something… wrong with me. so it started to spawn mithril weapons, flaming weapons, armors of great health, trying to lure me to pick it up. but no, no way: i can't use the weapon properly anyway. an AoGH… NO. out of desperation it spawned scroll of withing (hoping that i'll with for some good gear), and i immediately asked for the belt of levitation. i am so smart!

yes, i know that danger level going up by itself as the time passes. i just want to see how long i could resist the temptation… until the game spawns some real monster to pwn me. it tried with a chameleon which polyed to kobold chieftan (or warlord), but i had scroll of teleportation and escaped. and then slashed the chameleon while it polyed to easy golem.

'cmon, game, spawn some Real Badass!
Jan 26, 4:24 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
yay. found interesting quirk which puzzled me for some time.

after i added item outlines (separate bitmap with outlined tiles), there was anomalous item which rendered without outlines. the only one item. it couldn't be possible: the game NEVER accesses non-outlined tiles in outline mode. it was just a small visual glitch, so i decided to investigate it later.

and finally, today i looked into it. and found interesting thing, which looks like a bug (or a lazy coding from devs). that item has one anomaly: its secondary material volume set to 0. somehow secondary material is specified, though, which led me think that it is used.

but the game doesn't care, and it simply removes every pixel not belonging to the main material from the tile bitmap. not only "unused secondary", but every other "non-main" pixel. which basically wipes any possible pixelart… and outlines, as they don't belong to material color ranges.

easy to see: take the clock trinket, and set secondary material volume to 0. KABOOM! the whole clock art disappears, leaving only 1-pixel circle.

i believe that this is either an oversight (lazy coding, simplier comparison), or there was some deeper idea behind this, but i doubt it was ever developed further.

actually, it is not clear what to do with "pixelart tiles" in this case: should non-material pixels left untouched, or should we wipe them? both solutions have their uses in different circumstances. for now i think i'll change the code to wipe only "material" pixels, leaving other pixels untouched.

by the way, clock trinkets should be fixed: they actually should have two proper materials: the clock face as primary, and that wooden… how is it called? locker? is definitely a secondary material. why can't we make golden lockers, for example?
Jan 26, 5:00 am
Joined: Sep 5, 2010
Interests: make more ivans!
Posts: 244
and by the way… thank you all once more for Aslona route! i guess it's mostly red_kangaroo's work, right? (i haven't looked at git logs, it's just a wild guess). anyway, thanks to everybody involved. i like it so far, and for me it feels like an integral part of the game, made with "IVAN spirit" in mind. i haven't played it much yet, though — mostly because i am too lazy to sail to Aslona. (i REALLY need to implement auto-travel!) yet ~1/6 of my games is Aslona route. cannot say anything about balance, because i never even made to Oree without WM, but i managed to explore starting levels of GF and FC before having my ass handed to me, so they at least as playable as other parts of the game.

p.s.: we need to replace player's icon with a ship icon while sailing. sadly, i cannot draw even to save my life.
Jump to