Troll
- Posts:
- 121
- Group:
- Members
- Member
- #214
- Joined:
- January 26, 2011
|
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; }
|