Welcome Guest [Log In] [Register]
Welcome to Dominions 5 Mods. We hope you enjoy your visit.


You're currently viewing our forum as a guest. This means you are limited to certain areas of the board and there are some features you can't use. If you join our community, you'll be able to access member-only sections, and use many member-only features such as customizing your profile, sending personal messages, and voting in polls. Registration is simple, fast, and completely free.


Join our community!


If you're already a member please log in to your account to access all of our features:

Username:   Password:
Add Reply
How the Void Gate works
Topic Started: May 5 2015, 06:31 PM (4,419 Views)
iRFNA
Troll
Alright, here's the step by step process by which the void gate operates:

For a unit to be a candidate to summon from the void gate, it needs to have a positive health and province, but I don't think it's possible for you to summon with a dead unit or one off the map anyway (that is not dead which can eternal lie?). It needs to have astral magic, but it doesn't matter how much it has. Finally, there is a chance for either a summoning to happen or not.

A unit has a "summon chance" property that starts at 0. When it enters the void gate, summon chance is always increased by 20. That is the percent chance that the unit is able to summon from the void gate. If a summoning occurs, the chance is set back to 0. So every unit has a sequential 20%, 40%, 60%, 80%, then 100% chance to summon from the void gate until it summons something, then it is reset back to starting at 20% for the time after that. The summoning doesn't need to be useful though... summoning something that attacks you will also reset this value. Summon chance will persist on the unit. If a unit enters the void gate twice without summoning anything, goes off to war, and comes back to try again it will start at 60%.

Using my lack of probability knowledge, I've made this equation to describe the average turns per summon. It comes out at ~2.5 turns per summon. With the general case of 20% of summons attacking the summoner (described below), it's about ~3.13 turns per successful summon.

If a unit succeeds at the chance to summon, the game then rolls a value to determine what is summoned. The roll is:

summon roll = unit summoning ability + 2d6 (not open)

A summon roll will be 2 to 12 higher than the unit's summoning ability. This is important for getting the really nifty summons which require higher rolls. A summoning ability of 2 will protect the unit from getting a horror attack (a roll under 4).

After this roll is made, the unit's summoning ability is increased by 0.5 to 1.5. This increase will not apply to this summon's roll. While the game will display the rounded down value, an extra .5 will still be stored.

The game then grabs the units corresponding to the roll. However, there is a 50% chance that the roll will be ignored if astral corruption is up. In that case, there is either a 75% chance of getting the horror attack roll or a 25% chance of the eater of dreams munching on your summoner.

Assuming astral corruption didn't ruin your day, the normal unit summoning table is used. There is a 20% chance the summons will attack the summoner. This is modified on two cases which I'll note in the table.

The table is setup like this:
Summon Roll: Unit (Unit Count) - 20% chance to attack unless otherwise stated

2 to 3: Horror (1) - 100% chance to attack
4 to 5: Lesser Otherness (1 to 6)
6: Vile Thing (1 to 4)
7: Thing of Many Eyes (1 to 3)
8: Thing From The Void (1 to 3)
9: Elder Thing (1 to 5)
10: Formless Spawn (1 to 4)
11: Otherness (1 to 4)
12: Thing From Beyond (1 to 3)
13: Dweller-In-The-Deep (1 to 2) - 40% chance to attack
14: Greater Otherness (1 to 4)
15: Thing That Should Not Be (1)
16: Vastness (1)
17: Greater Otherness (1)
18: Visitor (1) - Can only have one Visitor, if you already have one then you get a Greater Otherness
19: Greater Otherness (1)
20: Vastness (1)
21 and greater: Greater Otherness (1 to 2)

The chance of being attacked is then multiplied by 4 if your nation isn't R'lyeh, to a base of 80%. Friends don't let friends use captured void gates!

Now that we've got our units, it's time to try to make things go wrong! And oh man, there are so many ways this can go wrong. First there is a 2% chance for the unit to get feebleminded. There's no way to reduce this chance. Good luck!

Afterward is getting lost in time and space or gaining some madness. The base chance for either is 65%. This chance is divided by the unit's void sanity and rounded down, so a 10 void sanity unit has a 6% chance of either. These chances are done independently and both can happen at once.

If the unit is chosen to get some madness, an open roll of 65 / void sanity is done. A unit without void sanity rolls an open 1d65 but a 10 void sanity illithid rolls 1d6. If the roll is greater than 100, the unit is given 100 madness and a free ticket to the R'lyeh asylum. Otherwise, a different open roll of 65 / void sanity is added to the unit's madness.

It is possible for a unit to be feebleminded, given 100 madness, and thrown into oblivion all from a single step into the void gate. But don't worry, the summoning will complete regardless.

And that is the final step. Units are summoned, and if the chance to attack happens then they will attack our adventurous summoner rather than serving the one true god.

Here's the code with my sloppy annotations:

Code:
 
int __cdecl voidsummon(signed int unitid)
{
 int result; // eax@1
 int v2; // edi@1
 bool healthiszero; // zf@2
 bool healthisneg; // sf@2
 int province; // ecx@2
 int effect205; // esi@5
 int summonskill; // esi@6
 int summonresult; // ebp@6
 int v9; // eax@6
 int unitcount; // edi@7
 signed int v11; // eax@9
 int summonunitid; // esi@10
 __int16 v13; // dx@18
 __int16 v14; // ax@48
 int sanitything0; // ebx@52
 int sanitything1; // ebp@52
 signed int voidsanity; // ecx@52
 unsigned int v18; // eax@55
 int v19; // edx@55
 signed int v20; // eax@60
 unsigned int v21; // ebx@64
 unsigned int v22; // ebp@68
 int v23; // ebx@70
 unsigned int lostsanitymaybe; // eax@70
 char *v25; // esi@70
 char *v26; // [sp-24h] [bp-240h]@71
 char *v27; // [sp-20h] [bp-23Ch]@71
 unsigned int v28; // [sp+8h] [bp-214h]@1
 int chanceofattack; // [sp+Ch] [bp-210h]@7
 unsigned int v30; // [sp+10h] [bp-20Ch]@1
 int v31; // [sp+14h] [bp-208h]@2
 int v32; // [sp+18h] [bp-204h]@1
 int couldgetlost; // [sp+1Ch] [bp-200h]@56
 int v34; // [sp+20h] [bp-1FCh]@1
 int v35; // [sp+24h] [bp-1F8h]@71
 unsigned int v36; // [sp+218h] [bp-4h]@1

 v36 = (unsigned int)&v28 ^ __security_cookie;
 v32 = -1;
 sub_10F0AA0("host: voidsummon cnr %d\n", unitid);
 sub_1175F30(unitid < 0, "h_vs: bad cnr");
 result = 208 * unitid;
 v2 = dword_4C1F5C4[52 * unitid];
 v30 = 208 * unitid;
 v34 = v2;
 if ( v2 < 0
   || (result = 112 * v2,
       healthiszero = unithealth[56 * v2] == 0,
       healthisneg = unithealth[56 * v2] < 0,
       province = unitprovince[56 * v2],
       v28 = 112 * v2,
       v31 = province,
       healthisneg | healthiszero)             // unit needs to have health
   || province <= 0                            // unit needs a valid province
   || (result = getmagic(unitid, 4), result <= 0)// gets astral magic paths, must be > 0
   || (addtouniteffect(v2, 205, 20, 1),
       effect205 = getuniteffect(unitid, 205, 1),
       result = randnum(100),
       effect205 <= result) )                  // adds 20 to effect 205, check if effect 205 <= rand(100)
   return result;
 addtouniteffect(v2, 205, -effect205, 1);      // add negative effect 205 back to it, setting it to zero
 summonskill = getuniteffect(unitid, 206, 1) / 2;// effect 206 is summoning skill
                                               // the returned value is 2x higher than the displayed value in-game
 summonresult = summonskill + normalroll(6, 2);
 v9 = singleroll(3);                           // number from 1 to 3
 addtouniteffect(v2, 206, v9, 1);              // increase summoning skill by 1 to 3 (0.5 to 1.5 in-game)
 do
 {
   chanceofattack = 20;
   unitcount = 1;                              // defaults to 1 unit
   if ( isritualactive(57, -1, -1) < 0 || randnum(100) >= 50 )// if astral corruption is up, 50% chance of horrors
   {
     if ( summonresult < 21 )
     {
       if ( summonresult == 20 )
       {
         summonunitid = 762;                   // vastness
       }
       else
       {
         if ( summonresult < 17 )
         {
           switch ( summonresult )
           {
             case 16:
               summonunitid = 762;             // vastness
               break;
             case 15:
               summonunitid = 751;             // thing that should not be
               break;
             case 14:
               summonunitid = 754;             // greater otherness
               unitcount = singleroll(4);
               break;
             case 13:
               summonunitid = 759;             // dweller-in-the-deep
               chanceofattack = 40;
               unitcount = singleroll(2);
               break;
             case 12:
               summonunitid = 750;             // thing from beyond
               unitcount = singleroll(3);
               break;
             case 11:
               summonunitid = 755;             // otherness
               unitcount = singleroll(4);
               break;
             case 10:
               summonunitid = 966;             // formless spawn
               unitcount = singleroll(4);
               break;
             case 9:
               summonunitid = 752;             // elder thing
               unitcount = singleroll(5);
               break;
             case 8:
               summonunitid = 753;             // thing from the void
               unitcount = singleroll(3);
               break;
             case 7:
               summonunitid = 758;             // thing of many eyes
               unitcount = singleroll(3);
               break;
             case 6:
               summonunitid = 757;             // vile thing
               unitcount = singleroll(4);
               break;
             default:
               if ( summonresult < 4 )
               {
                 chanceofattack = 100;
LABEL_45:
                 summonunitid = 308;           // horror
                 break;
               }
               summonunitid = 756;             // lesser otherness
               unitcount = singleroll(6);
               break;
           }
         }
         else                                  // summonresult >= 17 && summonresult < 20
         {
           if ( summonresult != 18 || hashero(1406) )
           {
             summonunitid = 754;               // greater otherness
           }
           else                                // summonresult 18 can summon a visitor
           {
             v13 = herocount++ + 1 >= 200;     // can only have 200 heroes
             summonunitid = 1406;              // visitor
             sub_1175F30(v13, "too many usedheroes");
             heroes[herocount] = 1406;
           }
         }
       }
     }
     else                                      // summonresult >= 21
     {
       summonunitid = 754;                     // greater otherness
       unitcount = singleroll(2);
     }
   }
   else                                        // astral corruption horror attack
   {
     v11 = randnum(100);
     chanceofattack = 100;
     if ( v11 >= 25 )                          // 75% chance to go to summonresult < 4 (horrors)
                                               // otherwise you get the eater of dreams
       goto LABEL_45;
     summonunitid = 651;                       // eater of dreams
   }
 }
 while ( unitprops[64 * summonunitid] & 0x800 && !(provterrains[78 * v31] & 4) );// checks if the unit type to be summoned is aquatic and if the void gate province terrain is sea
                                               // if the unit isn't aquatic it aborts the loop... i guess if it is aquatic, it needs to make sure it is being summoned into the sea
 v14 = unitnation[v28 / 2];                    // national ID of the player that owns this unit
 if ( v14 != 88 && v14 != 92 && v14 != 84 )    // if the player isn't r'lyeh then 4x chance of being attacked
   chanceofattack *= 4;
 sanitything0 = 65;                            // base 65% chance to be lost in time and space
 sanitything1 = 65;                            // base 65% chance to get some madness
 voidsanity = getuniteffect(unitid, 277, 1);   // effect 277 is void sanity
 if ( voidsanity > 1 )
 {
   sanitything0 = 65 / voidsanity;
   sanitything1 = 65 / voidsanity;
 }
 if ( randnum(100) < 2 )                       // 2% chance of being feebleminded
 {
   v18 = v28;
   v19 = dword_2ACA524[v28 / 4];
   *(int *)((char *)unitflagthing0 + v18) |= (unsigned int)&byte_1FFF968[1688];// this indicates failure
   *(int *)((char *)dword_2ACA524 + v18) = v19;
   indicsanityloss[v30] = 0;
 }
 couldgetlost = 0;
 if ( randnum(100) < sanitything1 )            // sanitything1 chance of happening
   couldgetlost = 1;                           // triggers lost in time and space
 if ( randnum(100) < sanitything0 )            // sanitything0 chance of happening
 {                                             // triggers madness
   if ( openroll(sanitything0) <= 100 )        // rolls an open die of sanitything0 sides, if it is less than 100 then the unit is given an open die of sanitything0 madness
     v20 = openroll(sanitything0);
   else
     v20 = 100;                                // if the open die above was greater than 100, the unit gets 100 madness
   addtouniteffect(v34, 309, v20, 1);          // effect 309 is madness
 }
 if ( randnum(100) >= chanceofattack )
 {                                             // successful summoning
   if ( summonunitid == 1406 )                 // special case for visitor
   {
     goodsummon2(-1, 1406, 0, unitnation[v28 / 2], v31);
     v22 = v30;
   }
   else
   {
     v22 = v30;
     goodsummon1(summonunitid, unitnation[v28 / 2], unitcount, v31, dword_4C1F5C8[v30 / 4]);
   }
   v23 = didsummon(-1, unitnation[v28 / 2], 2, unitid);
   lostsanitymaybe = (unsigned int)&byte_1FFF968[1688] & unitflagthing0[v28 / 4];
   v25 = &aNoOne[256 * summonunitid];
   v32 = v23;
   if ( lostsanitymaybe )
   {
     getunitname(unitcount, v25, (int)&v35);
     v27 = (char *)dword_4C1F5A0 + v22;
     v26 = "%s's summoning was successful, but unfortunately his mind was permanently damaged in the process.\n\n %d %s responded to the summoning. ";
   }
   else
   {
     getunitname(unitcount, v25, (int)&v35);
     v27 = (char *)dword_4C1F5A0 + v22;
     v26 = "%s's summoning was successful.\n\n %d %s responded to the summoning. ";
   }
   result = messagething(v23, v26, (char)v27);
   v21 = v28;
 }
 else                                          // attacked by summons
 {
   v21 = v28;
   if ( (unsigned int)&byte_1FFF968[1688] & unitflagthing0[v28 / 4] )// so any kind of bit overlap will trigger this, unk was some crazy value
                                               // 01 A2 43 4B
   {
     v32 = didsummon(-1, unitnation[v28 / 2], 1, v31);
     messagething(
       v32,
       "%s's summoning was a complete failure, his mind was permanently damaged and he was attacked by the creatures he tried to summon. ",
       (unsigned int)dword_4C1F5A0 + v30);
   }
   result = badsummon(unitid, summonunitid, unitcount, (int)&unk_21403BA, 1, 0);
 }
 if ( couldgetlost && *(__int16 *)((char *)unithealth + v21) > 0 )
 {
   if ( v32 < 0 )
     v32 = didsummon(-1, *(__int16 *)((char *)unitnation + v21), 1, v31);
   messagething(v32, "%s is lost in time and space. ", (unsigned int)dword_4C1F5A0 + v30);
   *(__int16 *)((char *)unitprovince + v21) = -11;// unit province set to -11
   result = sub_1106980();
 }
 return result;
}
Offline Profile Quote Post Goto Top
 
Ohlmann
Dom 5 Beta Team
Thanks for the work !

By the way, as far as I know, the Strange House In The Mist use the same mechanism. If you find it, don't throw anything precious in it if you're not R'lyeh.
Worthy Heroes - UW Expanded
Offline Profile Quote Post Goto Top
 
ioticus
Member Avatar
Tartarian
I was always told that magic and luck scales have an effect on void summoning. Is that not true?
Offline Profile Quote Post Goto Top
 
« Previous Topic · Testing and Technical Talk · Next Topic »
Add Reply

Skin created by Nikku from Zathyus Networks Resources