Advertisement
Guest User

Untitled

a guest
Oct 12th, 2020
344
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 29.76 KB | None | 0 0
  1. ZVSE2
  2. ; Author: Berserker aka EtherniDee
  3. ; Version: 2.0
  4. ; Engine: ERM 2.0+
  5. ; Requires: ERA 3.0.5+
  6.  
  7. ; === TYPES ===
  8. ; TFactions = array ? of TFaction;
  9. ; Represents all registered factions, where each index is real faction ID + 1 (thus Neutrals are 0).
  10.  
  11. ; TFaction = array ? of MonId: integer;
  12. ; Represents all registered monsters of single faction. Neutrals with speicifed shadow faction are treated
  13. ; as real faction creatures. For instance, if neutral Peasant has shadow faction TOWN_CASTLE, then it will
  14. ; be treated as TOWN_CASTLE member, though preserving it's neutral background/morale and attributes.
  15.  
  16. ; TNeutrals = record
  17. ; Stacks: array 7 of record
  18. ; MonType: integer;
  19. ; Quantity: integer; calculated real number of monsters
  20. ; end;
  21. ;
  22. ; SpreadMask: integer; Single bit for each 0..6 stack. If true, stack should be spread among free slots.
  23. ; end;
  24. ;
  25. ; Contains mixed neutrals, that human attacker will face in battle.
  26.  
  27. ; TNeutralsConfig = record
  28. ; Stacks: array 7 of record
  29. ; MonType: integer;
  30. ; RelativeQuantity: float; multiplier of total monsters power, used to change final stack quantity for humans
  31. ; end;
  32. ;
  33. ; SpreadMask: integer; Single bit for each 0..6 stack. If true, stack should be spread among free slots.
  34. ;
  35. ; Contains mixed neutrals configuration for adventure map tile.
  36. ; Each stack quantity will be calculated as TotalFightValue * RelativeQuantity / FightValue of particular monster type
  37.  
  38.  
  39. ; ===== PUBLIC =====
  40. !#VRi^mix_on^:S(TRUE); global mod flag for other mods
  41. !#VRi^mix_numNeutralStacks^:S3; Number of mixed neutral stacks in battle. FIXME/DELEME in the next versions
  42. !#VRi^mix_neutralStackScale^:S2; Multiplier for original neutrals quantity on adventure map. FIXME/DELEME in the next versions
  43. !#VRi^mix_netralStackScaleForHuman^:S2; Additional multiplier of neutrals power only for humans. FIXME/DELEME in the next versions
  44. ; === END PUBLIC ===
  45.  
  46.  
  47. !#SN:M(M_AUTO_ID)/0/(M_INT)/(M_STORED)/?i^mix_factionAllies^;
  48. !#VRi^mix_monsRegistrationState^:S0; // ????
  49. !#VRi^mix_registerRegularMonsters^:S(TRUE); // ????
  50. !#VRi^mix_moveNeutralsToFactions^:S(TRUE); // ????
  51.  
  52. ! !FU(min_GenerateFactionMonster):P;
  53. ! !SN:Vi^mix_fractionTables^/(MIX_FACTION_CONFLUX)/?(mons:y) V(mons)/14/?(monType:y);
  54. ! !IF:M^%(monType)^;
  55.  
  56. !?FU(OnAfterErmInstructions)&i^mix_moveNeutralsToFactions^<>(FALSE);
  57. !!MA:O(MON_GOLD_GOLEM)/(TOWN_TOWER);
  58. !!MA:O(MON_DIAMOND_GOLEM)/(TOWN_TOWER);
  59. !!MA:O(MON_AZURE_DRAGON)/(TOWN_TOWER);
  60. !!MA:O(MON_CRYSTAL_DRAGON)/(TOWN_CONFLUX);
  61. !!MA:O(MON_FAERIE_DRAGON)/(TOWN_RAMPART);
  62. !!MA:O(MON_RUST_DRAGON)/(TOWN_FORTRESS);
  63. !!MA:O(MON_ENCHANTER)/(TOWN_TOWER);
  64. !!MA:O(MON_SHARPSHOOTER)/(TOWN_RAMPART);
  65. !!MA:O(MON_HALFLING)/(TOWN_CASTLE);
  66. !!MA:O(MON_PEASANT)/(TOWN_CASTLE);
  67. !!MA:O(MON_BOAR)/(TOWN_STRONGHOLD);
  68. !!MA:O(MON_MUMMY)/(TOWN_NECROPOLIS);
  69. !!MA:O(MON_NOMAD)/(TOWN_STRONGHOLD);
  70. !!MA:O(MON_ROGUE)/(TOWN_CASTLE);
  71. !!MA:O(MON_TROLL)/(TOWN_STRONGHOLD);
  72.  
  73. !!re i/(MON_SUPREME_ARCHANGEL)/(MON_SACRED_PHOENIX):;
  74. !!VR(faction:y):Si -(MON_SUPREME_ARCHANGEL);
  75. !!MA:Oi/(faction);
  76. !!en:;
  77.  
  78. !!MA:O(MON_GHOST)/(TOWN_NECROPOLIS);
  79.  
  80. !!re i/(MON_FIRE_MESSENGER)/(MON_WATER_MESSENGER):;
  81. !!MA:Oi/(TOWN_CONFLUX);
  82. !!en:;
  83.  
  84. !!MA:O(MON_GORYNYCH)/(TOWN_FORTRESS);
  85. !!MA:O(MON_WAR_ZEALOT)/(TOWN_CASTLE);
  86. !!MA:O(MON_ARCTIC_SHARPSHOOTER)/(TOWN_TOWER);
  87. !!MA:O(MON_LAVA_SHARPSHOOTER)/(TOWN_INFERNO);
  88. !!MA:O(MON_NIGHTMARE)/(TOWN_NECROPOLIS);
  89. !!MA:O(MON_SANTA_GREMLIN)/(TOWN_TOWER);
  90. !!MA:O(MON_SYLVAN_CENTAUR)/(TOWN_RAMPART);
  91. !!MA:O(MON_SORCERESS)/(TOWN_CONFLUX);
  92. !!MA:O(MON_WEREWOLF)/(TOWN_STRONGHOLD);
  93. !!MA:O(MON_HELL_STEED)/(TOWN_INFERNO);
  94. !!MA:O(MON_DRACOLICH)/(TOWN_NECROPOLIS);
  95.  
  96. !?FU(mix_OnRegisterRegularMonsters)&i^mix_registerRegularMonsters^<>(FALSE);
  97. !!FU(mix_RegisterRegularMonsterRange):P(MON_PIKEMAN)/(MON_MAGIC_ELEMENTAL);
  98. !!FU(mix_RegisterRegularMonsterRange):P(MON_PIKEMAN)/(MON_MAGIC_ELEMENTAL);
  99. !!FU(mix_RegisterRegularMonsterRange):P(MON_ICE_ELEMENTAL)/(MON_ICE_ELEMENTAL);
  100. !!FU(mix_RegisterRegularMonsterRange):P(MON_MAGMA_ELEMENTAL)/(MON_MAGMA_ELEMENTAL);
  101. !!FU(mix_RegisterRegularMonsterRange):P(MON_STORM_ELEMENTAL)/(MON_STORM_ELEMENTAL);
  102. !!FU(mix_RegisterRegularMonsterRange):P(MON_ENERGY_ELEMENTAL)/(MON_TROLL);
  103. !!FU(mix_RegisterRegularMonsterRange):P(MON_FIRE_MESSENGER)/(MON_SANTA_GREMLIN);
  104. !!FU(mix_RegisterRegularMonsterRange):P(MON_SYLVAN_CENTAUR)/(MON_DRACOLICH);
  105.  
  106. !?FU(mix_OnRegisterRegularMonsters));
  107. !!FU:E;
  108. !!if&v1<>v1:;
  109. !!FU(ConstructBitMask):P7/0/3/?(mask:y);
  110. !!IF:M^Mask: %(mask)^;
  111. !!SN:M(M_AUTO_ID)/0/(M_INT)/(M_TRIGGER_LOCAL)/?(list:y);
  112. !!FU(DeconstructBitMask):P(mask)/(list);
  113. !!FU(Array_Join):P(list)/^ ^;
  114. !!IF:M^Bits: %s(result)^;
  115. !!FU(mix_SetFactionAllies):P(TOWN_RAMPART)/(TOWN_NECROPOLIS)/50/(TOWN_CONFLUX)/25;
  116. !!FU(mix_GetRandomBaseOrAlliedFaction):P(TOWN_TOWER)/?(fac1:y);
  117. !!FU(mix_GetRandomBaseOrAlliedFaction):P(TOWN_TOWER)/?(fac2:y);
  118. !!FU(mix_GetRandomBaseOrAlliedFaction):P(TOWN_TOWER)/?(fac3:y);
  119. !!IF:M^%(fac1) %(fac2) %(fac3)^;
  120. !!SN:Vi^mix_factionAllies^/3/?(towerAllies:y);
  121. !!FU(Array_Join):P(towerAllies)/^ ^;
  122. !!IF:M^%s(result)^;
  123. !!FU:E;
  124. !!en;
  125.  
  126. !!FU(mix_SetFactionAllies):P(TOWN_RAMPART)/(TOWN_NECROPOLIS)/50/(TOWN_CONFLUX)/25;
  127. !!SN:Mi^mix_factions^/2/?(faction:y);
  128. !!FU(Array_SortedUnique):P(faction);
  129. !!FU(Array_Join):P(faction)/^ ^;
  130. !!IF:M^%s(result)^;
  131.  
  132. !!FU(Array_Join):Pi^mix_monToFactionInd^/^ ^;
  133. !!IF:M^%s(result)^;
  134.  
  135. !!FU(mix_GenerateRandomMonster):P?(mon1:y);
  136. !!FU(mix_GenerateRandomMonster):P?(mon2:y);
  137. !!FU(mix_GenerateRandomMonster):P?(mon3:y);
  138. !!IF:M^%(mon1) %(mon2) %(mon3)^;
  139.  
  140. !!FU(mix_GenerateFactionMonster):P(TOWN_RAMPART)/(MIX_DISALLOW_ALLIED_FACTIONS)/?(mon1:y);
  141. !!FU(mix_GenerateFactionMonster):P(TOWN_RAMPART)/(MIX_DISALLOW_ALLIED_FACTIONS)/?(mon2:y);
  142. !!FU(mix_GenerateFactionMonster):P(TOWN_RAMPART)/(MIX_DISALLOW_ALLIED_FACTIONS)/?(mon3:y);
  143. !!IF:M^%(mon1) %(mon2) %(mon3)^;
  144.  
  145. !?FU(mix_RegisterRegularMonsterRange);
  146. !#VA(firstMonId:x); The first monster ID.
  147. !#VA(lastMonId:x); The last monster ID.
  148.  
  149. !!if&i^mix_monsRegistrationState^<>(MIX_MONS_ARE_REGISTERING):;
  150. !!SN:F^ShowErmError^/^The "mix_RegisterRegularMonsterRange" function can be called in "mix_OnRegisterRegularMonsters" event only^;
  151. !!FU:E;
  152. !!en;
  153.  
  154. !!if|(firstMonId)<(MON_FIRST)/(lastMonId)<(MON_FIRST)/(firstMonId)>(lastMonId)/(lastMonId)>(MIX_MAX_POSSIBLE_MON_ID):;
  155. !!SN:F^ShowErmError^/^Invalid monsters range to register: %(firstMonId)..%(lastMonId)^;
  156. !!FU:E;
  157. !!en;
  158.  
  159. ; Ensure, there is enough space in monster-to-faction table
  160. !!VR(minMonTableSize:y):S(lastMonId) +1;
  161. !!VR(monToFactionInd:y):Si^mix_monToFactionInd^;
  162. !!FU(Array_EnsureMinSize):P(monToFactionInd)/(minMonTableSize)/(MIX_UNSET_FACTION);
  163.  
  164. ; Start with already registered factions
  165. !!VR(factions:y):Si^mix_factions^;
  166. !!SN:M(factions)/?(numFactions:y);
  167.  
  168. ; Process each monster in the range
  169. !!re (mon:y)/(firstMonId)/(lastMonId):;
  170. ; Do not register same monster twice
  171. !!SN:V(monToFactionInd)/(mon)/?(factionInd:y);
  172. !!co&(factionInd:y)<>(MIX_UNSET_FACTION):;
  173.  
  174. ; Get monster faction and convert it to index
  175. !!VR(factionInd:y):S(INT_MIN);
  176. !!MA:O(mon)/?(factionInd);
  177. !!FU&(factionInd)=(INT_MIN):E;
  178. !!VR(factionInd):-(NO_TOWN);
  179.  
  180. ; Save monster faction index in monster to faction index map
  181. !!SN:V(monToFactionInd)/(mon)/(factionInd);
  182.  
  183. ; Allocate new factions if accessing faction with new index
  184. !!if&(factionInd)>=(numFactions):;
  185. !!VR(newNumFactions:y):S(factionInd) +1;
  186. !!SN:M(factions)/(newNumFactions);
  187.  
  188. !!re i/(numFactions)/(newNumFactions)/1/-1:;
  189. !!SN:M(M_AUTO_ID)/0/(M_INT)/(M_STORED)/?(faction:y) V(factions)/i/(faction);
  190. !!en:;
  191.  
  192. !!VR(numFactions):S(newNumFactions);
  193. !!en;
  194.  
  195. ; Add monster to specified faction
  196. !!SN:V(factions)/(factionInd)/?(faction:y) M(faction)/d1 V(faction)/-1/(mon);
  197.  
  198. !!VRi^mix_numMons^:+1;
  199. !!en:; re
  200. ; mix_RegisterRegularMonsterRange
  201.  
  202. !?FU(mix_SetFactionAllies);
  203. ; Set up to 7 ally factions for specified base faction. They may be used for random monsters generation.
  204. ; Base faction has weight 100. Each ally is added with some weight. Weight determines the chance to generate
  205. ; unit from base or any allied factions. For example, if you add Rampart 50 and Neutrals 10 to Castle,
  206. ; then whe total weight will be 100 + 50 + 10 = 160.
  207. ; Chance for Castle monster will be 100 / 160 * 100% = 62.5%.
  208. ; Chance for Rampart monster will be 50 / 160 * 100% = 31.25%.
  209. ; Chance for Neutrals monster will be 10 / 160 * 100% = 6.25%.
  210.  
  211. !#VA(baseFaction:x); Base faction ID to set ally factions for.
  212. !#VA(variableArgs:x); ... Other arguments are pairs of (Faction ID, Faction Weight).
  213.  
  214. !!if|(baseFaction)<(NO_TOWN)/(baseFaction)>(MIX_MAX_POSSIBLE_FACTION_ID):;
  215. !!SN:F^ShowErmError^/^Invalid "baseFaction" argument: %(baseFaction)^;
  216. !!FU:E;
  217. !!en;
  218.  
  219. !!VR(baseFactionInd:y):S(baseFaction) -(NO_TOWN);
  220.  
  221. ; Check if any ally pair is specified
  222. !!FU:A?(numArgs:y);
  223. !!VR(numAllies:y):S(numArgs) -(@variableArgs) +1 :2;
  224. !!FU&(numAllies)<=0:E;
  225.  
  226. ; Get base faction allies array
  227. !!VR(factionAllies:y):Si^mix_factionAllies^;
  228. !!SN:M(factionAllies)/?(numFactions:y);
  229.  
  230. !!if&(baseFactionInd)>=(numFactions):;
  231. !!VR(numFactions):S(baseFactionInd) +1;
  232. !!SN:M(factionAllies)/(numFactions);
  233. !!en;
  234.  
  235. !!SN:M(factionAllies)/(baseFactionInd)/?(baseFactionAllies:y);
  236.  
  237. !!if&(baseFactionAllies)=0:;
  238. !!SN:M(M_AUTO_ID)/0/(M_INT)/(M_STORED)/?(baseFactionAllies:y) V(factionAllies)/(baseFactionInd)/(baseFactionAllies);
  239. !!el:;
  240. !!SN:M(baseFactionAllies)/0;
  241. !!en;
  242.  
  243. ; Start filling the array with specified factions
  244. !!VR(lastArgInd:y):S(numAllies) -1 *2 +(@variableArgs);
  245. !!VR(totalWeight:y):S(MIX_BASE_FACTION_WEIGHT);
  246.  
  247. !!re i/(@variableArgs)/(lastArgInd)/2:;
  248. !!VR(allyFaction:y):Sxi;
  249. !!VR(weightArgInd:y):Si +1;
  250. !!VR(allyFactionWeight:y):Sx(weightArgInd);
  251.  
  252. !!if|(allyFaction)<(NO_TOWN)/(allyFaction)>(MIX_MAX_POSSIBLE_FACTION_ID):;
  253. !!SN:F^ShowErmError^/^Invalid ally faction ID: %(allyFaction)^;
  254. !!FU:E;
  255. !!en;
  256.  
  257. !!if|(allyFactionWeight)<=0/(allyFactionWeight)>1000000:;
  258. !!SN:F^ShowErmError^/^Invalid ally faction weight: %(allyFactionWeight)^;
  259. !!FU:E;
  260. !!en;
  261.  
  262. !!VR(allyFactionInd:y):S(allyFaction) -(NO_TOWN);
  263. !!VR(totalWeight):+(allyFactionWeight);
  264.  
  265. !!SN:M(baseFactionAllies)/d2 V(baseFactionAllies)/-2/(allyFactionInd)/(allyFactionWeight);
  266. !!en:;
  267.  
  268. ; Save total weight in the last allies array
  269. !!SN:M(baseFactionAllies)/d1 V(baseFactionAllies)/-1/(totalWeight);
  270.  
  271. !?FU(mix_GetRandomBaseOrAlliedFaction);
  272. ; Returns either base faction ID or random allied faction ID, based on faction allies configuration.
  273. !#VA(baseFaction:x); Base faction ID.
  274. !#VA(result:x); Result.
  275. !!VR(result):S(baseFaction);
  276. !!FU|(baseFaction)<(NO_TOWN)/(baseFaction)>(MIX_MAX_POSSIBLE_FACTION_ID):E;
  277. !!VR(baseFactionInd:y):S(baseFaction) -(NO_TOWN);
  278.  
  279. !!VR(factionAllies:y):Si^mix_factionAllies^;
  280. !!SN:M(factionAllies)/?(numFactions:y);
  281. !!FU&(baseFactionInd)>=(numFactions):E;
  282.  
  283. !!SN:V(factionAllies)/(baseFactionInd)/?(baseFactionAllies:y);
  284. !!FU&(baseFactionAllies)=0:E;
  285. !!SN:M(baseFactionAllies)/?(numAllies:y) V(baseFactionAllies)/-1/?(totalWeight:y);
  286. !!VR(numAllies):-1 :2;
  287.  
  288. !!VR(randomWeight:y):R0/1/(totalWeight);
  289. !!FU&(randomWeight)<=(MIX_BASE_FACTION_WEIGHT):E;
  290.  
  291. !!VR(weight:y):S(MIX_BASE_FACTION_WEIGHT);
  292.  
  293. !!re i/0/(numAllies)/1/-1:;
  294. !!VR(allyDataPtr:y):Si *2;
  295. !!SN:V(baseFactionAllies)/(allyDataPtr)/?(allyFactionInd:y)/?(allyFactionWeight:y);
  296. !!VR(weight):+(allyFactionWeight);
  297.  
  298. !!br&(weight)>=(randomWeight):;
  299. !!en:;
  300.  
  301. !!VR(result):S(allyFactionInd) +(NO_TOWN);
  302.  
  303. !?FU(mix_GenerateRandomMonster);
  304. ; Generates regular random monster of any faction and returns its ID or NO_MON on error.
  305. !#VA(result:x);
  306. !!VR(result):S(NO_MON);
  307.  
  308. !!VR(numMons:y):Si^mix_numMons^;
  309. !!FU&(numMons)<=0:E;
  310.  
  311. !!VR(factions:y):Si^mix_factions^;
  312. !!SN:M(factions)/?(numFactions:y);
  313.  
  314. !!VR(monInd:y):R0/1/(numMons) -1;
  315. !!VR(factionStartMonInd:y):S0;
  316.  
  317. !!re i/0/(numFactions)/1/-1:;
  318. !!SN:V(factions)/i/?(faction:y);
  319. !!SN:M(faction)/?(numFactionMons:y);
  320. !!VR(factionEndMonInd:y):S(factionStartMonInd) +(numFactionMons);
  321.  
  322. !!if&(monInd)<(factionEndMonInd):;
  323. !!VR(monInd):-(factionStartMonInd);
  324. !!SN:V(faction)/(monInd)/?(result);
  325. !!FU:E;
  326. !!en;
  327.  
  328. !!VR(factionStartMonInd:y):S(factionEndMonInd);
  329. !!en:;
  330.  
  331. !?FU(mix_GenerateFactionMonster);
  332. ; Generates random monster from particular faction or even allied factions.
  333. !#VA(faction:x); Faction/Town ID or (NO_TOWN) for neutrals.
  334. !#VA(allowAlliedFactions:x); Allow to generate from allied factions (TRUE) or not (FALSE). Default: (FALSE).
  335. !#VA(result:x); Result monster ID or (NO_MON) on error.
  336.  
  337. !!VR(result):S(NO_MON);
  338.  
  339. !!VR(numMons:y):Si^mix_numMons^;
  340. !!FU&(numMons)<=0:E;
  341.  
  342. ; Get final faction ID and index
  343. !!FU(mix_GetRandomBaseOrAlliedFaction)&(allowAlliedFactions)<>(FALSE):P(faction)/?(faction);
  344. !!VR(factionInd:y):S(faction) -(NO_TOWN);
  345.  
  346. ; Check if there exists such faction with at least single creature
  347. !!VR(factions:y):Si^mix_factions^;
  348. !!SN:M(factions)/?(numFactions:y);
  349. !!FU|(factionInd)<0/(factionInd)>=(numFactions):E;
  350. !!SN:V(factions)/(factionInd)/?(factionMons:y);
  351. !!SN:M(factionMons)/?(numFactionMons:y);
  352. !!FU&(numFactionMons)<=0:E;
  353.  
  354. ; Write random faction monster ID to result
  355. !!VR(monInd:y):R0/1/(numFactionMons) -1;
  356. !!SN:V(factionMons)/(monInd)/?(result);
  357.  
  358. ; Reset settings of regular monster
  359. !?FU(mix_ResetRegularMonsterSettings)&i^mix_initedMonSettings^=1;
  360. !!VRi^mix_initedMonSettings^:S0;
  361. !!VR(factions:y):Si^mix_factions^;
  362. !!SN:M(factions)/?(numFactions:y);
  363.  
  364. !!re i/0/(numFactions)/1/-1:;
  365. !!SN:V(factions)/0/?(faction:y);
  366. !!SN:M(faction);
  367. !!en:;
  368.  
  369. !!SN:Mi^mix_factions^ Mi^mix_factionAllies^;
  370.  
  371. !?FU(OnAdvMapTileHint)&y1<>y1; DISABLED, better see unscaled value in current implementation
  372. ; WHY????
  373. !#VA(x:x) (y:x) (z:x);
  374. !!OB(x)/(y)/(z):T?(objType:y) U?(monType:y);
  375. !!FU&(objType)<>(OBJ_MONSTER):E;
  376. !!FU(mix_GetTileNeutralsConfig):P(x)/(y)/(z)/?(config:y);
  377. !!FU&(config)=0:E;
  378. !!SN:H^monname^/(monType)/1/?(monName:z);
  379. !!MO(x)/(y)/(z):G?(monNum:y);
  380. !!VR(monNum):*i^mix_netralStackScaleForHuman^;
  381. !!VR(monNum)&(monNum)<0:S(INT32_MAX);
  382. !!FU(mix_MonQtyToFuzzyText):P(monNum);
  383. !!MM:M^%(monName): %S(result)^;
  384.  
  385. !?FU(OnAdventureMapRightMouseClick)&y1<>y1; DEBUG CODE
  386. !!CM:R0 P?(x:y)/?(y:y)/?(z:y);
  387. !!FU(mix_GetTileNeutralsConfig):P(x)/(y)/(z)/?(config:y)/(MIX_AUTOCREATE_NEUTRALS_CONFIG);
  388.  
  389. !#VA(relQts[3]:e);
  390. !!VR(relQts[0]):S333 :100;
  391. !!VR(relQts[1]):S333 :100;
  392. !!VR(relQts[2]):S333 :100;
  393. !!SN:V(config)/0/2/(relQts[0])/9/(relQts[1])/13/(relQts[2]);
  394.  
  395. !!SN:M(M_AUTO_ID)/(MIX_NEUTRALS_STRUCT_SIZE)/(M_INT)/(M_TRIGGER_LOCAL)/?(neutrals:y);
  396. !!FU(mix_ReadTileNeutrals):P(x)/(y)/(z)/(neutrals);
  397. !#VA(monTypes[3]:y) (monNums[3]:y);
  398. !!SN:V(neutrals)/0/?(monTypes[0])/?(monNums[0])/?(monTypes[1])/?(monNums[1])/?(monTypes[2])/?(monNums[2]);
  399. !!IF:M^%(monTypes[0])/%(monNums[0]) %(monTypes[1])/%(monNums[1]) %(monTypes[2])/%(monNums[2])^;
  400.  
  401. !?FU(OnAdventureMapRightMouseClick);
  402. !!CM:P?(x:y)/?(y:y)/?(z:y);
  403. !!OB(x)/(y)/(z):T?(objType:y);
  404. !!FU&(objType)<>(OBJ_MONSTER):E;
  405.  
  406. !!SN:M(M_AUTO_ID)/(MIX_NEUTRALS_STRUCT_SIZE)/(M_INT)/(M_TRIGGER_LOCAL)/?(neutrals:y);
  407. !!FU(mix_ReadTileNeutrals):P(x)/(y)/(z)/(neutrals);
  408. !!SN:V(neutrals)/0/?(firstStackType:y);
  409. !!FU&(firstStackType)=(NO_MON):E;
  410.  
  411. !!VR(showFuzzyNumbers:y):S(TRUE);
  412. !!VR(disablePopup:y):S(FALSE);
  413. !!FU(mix_OnViewNeutrals):P?(showFuzzyNumbers)/?(disablePopup)/(x)/(y)/(z);
  414. !!FU&(disablePopup)<>(FALSE):E;
  415.  
  416. !!CM:R0;
  417. !!VR(text:z):S^^;
  418.  
  419. !!re i/0/(MIX_MAX_NEUTRAL_STACKS)/1/-1:;
  420. !!VR(pairInd:y):Si *2;
  421. !!SN:V(neutrals)/(pairInd)/?(monType:y)/?(monNum:y);
  422.  
  423. !!if&(monType)<>(NO_MON):;
  424. !!SN:H^monname^/(monType)/1/?(monName:z);
  425. !!VR(monNumStr:z):S^%(monNum)^;
  426.  
  427. !!if&(showFuzzyNumbers)<>(FALSE):;
  428. !!FU(mix_MonQtyToFuzzyText):P(monNum);
  429. !!VR(monNumStr):Ss^result^;
  430. !!en;
  431.  
  432. !!VR(text):+^{%(monName)}: %(monNumStr)
  433. ^;
  434. !!en;
  435. !!en:;
  436.  
  437. !!IF:M1/4/(text);
  438.  
  439. !?FU(mix_MonQtyToFuzzyText);
  440. !#VA(monNum:x);
  441. ; Returns result in s^result^
  442. !!if&(monNum)<=4:;
  443. !!VRs^result^:S^1-4^;
  444. !!el&(monNum)<=9:;
  445. !!VRs^result^:S^5-9^;
  446. !!el&(monNum)<=19:;
  447. !!VRs^result^:S^10-19^;
  448. !!el&(monNum)<=49:;
  449. !!VRs^result^:S^20-49^;
  450. !!el&(monNum)<=99:;
  451. !!VRs^result^:S^50-99^;
  452. !!el&(monNum)<=249:;
  453. !!VRs^result^:S^100-249^;
  454. !!el&(monNum)<=499:;
  455. !!VRs^result^:S^250-499^;
  456. !!el&(monNum)<=999:;
  457. !!VRs^result^:S^500-999^;
  458. !!el&(monNum)<1000000:;
  459. !!VR(thousandInd:y):S(monNum) :1000;
  460. !!FU(mix_IntLog2):P(thousandInd)/?(thousandPower:y);
  461. !!VR(borderValue:y):S1 Sd<<(thousandPower) *1000 -1;
  462. !!VR(thousandPower)&(monNum)<=(borderValue):-1;
  463. !!VR(rangeStart:y):S1 Sd<<(thousandPower);
  464. !!VRs^result^:S^%(rangeStart)K+^;
  465. !!el:;
  466. !!VR(billionInd:y):S(monNum) :1000000;
  467. !!FU(mix_IntLog2):P(billionInd)/?(billionPower:y);
  468. !!VR(borderValue:y):S1 Sd<<(billionPower) *1000000 -1;
  469. !!VR(borderValue)&(borderValue)<0:S(INT32_MAX);
  470. !!VR(billionPower)&(monNum)<=(borderValue):-1;
  471. !!VR(rangeStart:y):S1 Sd<<(billionPower);
  472. !!VRs^result^:S^%(rangeStart)M+^;
  473. !!en;
  474.  
  475. !?FU(mix_IntLog2);
  476. ; Returns Ceil(Log2(N))
  477. !#VA(value:x) (result:x);
  478. !!VR(result):S0;
  479. !!FU&(value)<=0:E;
  480.  
  481. !!VR(testValue:y):S1;
  482.  
  483. !!re i:;
  484. !!br|(testValue)>=(value)/(testValue)<0:;
  485. !!VR(result):+1;
  486. !!VR(testValue):Sd<<1;
  487. !!en:;
  488.  
  489. !!VR(result)&(testValue)>1073741824:+1;
  490.  
  491. !?FU(OnEveryDay)&i^timerDay^=1/i^timerOnce^=1;
  492. !!FU(mix_InitializeNeutrals):P;
  493.  
  494. !?FU(mix_InitializeNeutrals);
  495. !!UN:U(OBJ_MONSTER)/(ANY_OBJ)/?(numMapMons:y);
  496. !!FU&(numMapMons)<=0:E;
  497.  
  498. !!VRv2:S-1;
  499. !!VR(singleStackRelQty:e):S1 *i^mix_netralStackScaleForHuman^ :i^mix_numNeutralStacks^;
  500.  
  501. !!re i/1/(numMapMons):;
  502. !!UN:U(OBJ_MONSTER)/(ANY_OBJ)/-1/2;
  503.  
  504. !!OB2:U?(origMonType:y);
  505. !!MO2:Gd*i^mix_neutralStackScale^;
  506.  
  507. !!FU(mix_GetTileNeutralsConfig):Pv2/v3/v4/?(config:y)/(MIX_AUTOCREATE_NEUTRALS_CONFIG);
  508. !!SN:V(config)/0/(origMonType)/(singleStackRelQty) V(config)/-1/5;
  509.  
  510. !!re j/1/i^mix_numNeutralStacks^/1/-1:;
  511. !!VR(randomMonType:y):S(NO_MON);
  512. !!FU(mix_GenerateRandomMonster):P?(randomMonType)/(origMonType);
  513.  
  514. ; Provide fallback if no user monster generation function is provided
  515. !!if&(randomMonType)=(NO_MON):;
  516. !!VR(randomMonType:y):T0/0/140;
  517. !!VR(randomMonType)&(randomMonType)=122:S141;
  518. !!VR(randomMonType)&(randomMonType)=124:S142;
  519. !!VR(randomMonType)&(randomMonType)=126:S143;
  520. !!VR(randomMonType)&(randomMonType)=128:S144;
  521. !!en;
  522.  
  523. !!VR(pairInd:y):Sj *2;
  524. !!SN:V(config)/(pairInd)/(randomMonType)/(singleStackRelQty);
  525. !!en:; re
  526. !!en:; re
  527.  
  528. !?FU(OnBeforeBattleUniversal);
  529. !!VRi^mix_isNeutralsBattle^:S0;
  530.  
  531. !?FU(OnBeforeBattleUniversal)&(ERM_FLAG_REAL_BATTLE);
  532. !#VA(heroes[2]:y) (owners[2]:y) (ai[2]:y);
  533. !!BA:O?(owners[0])/?(owners[1]) H?(heroes[0])/?(heroes[1]) P?(x:y)/?(y:y)/?(z:y);
  534. !!VR(ai):C(TRUE)/(TRUE);
  535. !!OW&(owners[0])<>(NO_OWNER):I(owners[0])/?(ai[0]);
  536. !!OW&(owners[1])<>(NO_OWNER):I(owners[1])/?(ai[1]);
  537.  
  538. ; We handle only battle of human player vs AI
  539. !!FU|(ai[0])=(TRUE)/(owners[1])<>(NO_OWNER):E;
  540.  
  541. ; Get original monster info, exit if siege or any error
  542. !!FU(mix_GetAdvMapMonInfo):P(x)/(y)/(z)/?(origMonType:y)/?(origMonNum:y);
  543. !!FU|(origMonType)=(NO_MON)/(origMonNum)<=0:E;
  544.  
  545. ; Calculate total fight value
  546. !!MA:F(origMonType)/?(origMonFightValue:y);
  547. !!VR(totalFightValue:e):S(origMonFightValue) *(origMonNum);
  548. !!FU&(totalFightValue)<=0:E;
  549.  
  550. ; Determine concrete neutral stacks for battle (other scripts/mods are totally ignored here)
  551. !!SN:M(M_AUTO_ID)/(MIX_NEUTRALS_STRUCT_SIZE)/(M_INT)/(M_TRIGGER_LOCAL)/?(neutrals:y);
  552. !!FU(mix_ReadTileNeutrals):P(x)/(y)/(z)/(neutrals);
  553. !!SN:V(neutrals)/0/?(firstStackType:y);
  554. !!FU&(firstStackType)=(NO_MON):E;
  555.  
  556. ; Assign stacks and remember total neutrals fight value
  557. !!VRi^mix_isNeutralsBattle^:S1;
  558. !!VR(neutralsFightValue:e):S0;
  559.  
  560. !!re i/0/(MIX_MAX_NEUTRAL_STACKS)/1/-1:;
  561. !!VR(pairInd:y):Si *2;
  562. !!SN:V(neutrals)/(pairInd)/?(monType:y)/?(monNum:y);
  563. !!BA:M(BATTLE_RIGHT)/i/(monType)/(monNum);
  564.  
  565. !!if&(monType)<>(NO_MON):;
  566. !!MA:F(monType)/?(monFightValue:y);
  567. !!VR(stackFightValue:e):S(monFightValue) *(monNum);
  568. !!VR(neutralsFightValue):+(stackFightValue);
  569. !!en;
  570. !!en:;
  571.  
  572. !!VR(neutralsFightValueWrapper:y):C(neutralsFightValue);
  573. !!VR(neutralsFightValueWrapper):C?i^mix_neutralsFightValue^;
  574.  
  575. ; Remember real battle coordinates in case some script tries to manipulate them
  576. !!VRi^mix_battleX^:S(x);
  577. !!VRi^mix_battleY^:S(y);
  578. !!VRi^mix_battleZ^:S(z);
  579.  
  580. !?FU(OnBeforeBattleUniversal);
  581. ; Call custom callback, allowing to log configurated pre-battle armies
  582. !!FU(mix_OnSetupBattleArmies):P;
  583.  
  584. !?FU(OnAfterBattleUniversal)&(ERM_FLAG_REAL_BATTLE)/i^mix_isNeutralsBattle^=(TRUE);
  585. ; Check if there are neutral stacks left, calculating total fight value
  586. !!VR(finalFightValue:e):S0;
  587.  
  588. !!re i/0/(MIX_MAX_NEUTRAL_STACKS)/1/-1:;
  589. !!BA:M(BATTLE_RIGHT)/i/?(monType:y)/?(monNum:y);
  590.  
  591. !!if&(monType)<>(NO_MON)/(monNum)>0:;
  592. !!MA:F(monType)/?(monFightValue:y);
  593. !!VR(stackFightValue:e):S(monFightValue) *(monNum);
  594. !!VR(finalFightValue):+(stackFightValue);
  595. !!en;
  596. !!en:;
  597.  
  598. ; Call custom callback, allowing to log battle casualities and implement, for instance, custom necromancy
  599. !!FU(mix_OnAnalyseBattleResults):P;
  600.  
  601. ; Exit if all neutrals are dead and clear neutrals config
  602. !!if&(finalFightValue)<=0:;
  603. !!FU(mix_ClearTileNeutralsConfig):Pi^mix_battleX^/i^mix_battleY^/i^mix_battleZ^;
  604. !!FU:E;
  605. !!en;
  606.  
  607. ; Recalculate new neutrals quantity on map as Ceil(Original quantity * Final Fight Value / Original Fight Value)
  608. !!FU(mix_GetAdvMapMonInfo):Pi^mix_battleX^/i^mix_battleY^/i^mix_battleZ^/?(origMonType:y)/?(origMonNum:y);
  609. !!VR(originalFightValueWrapper:y):Si^mix_neutralsFightValue^;
  610. !!VR(originalFightValueWrapper):C?(originalFightValue:e);
  611. !!VR(newAdvMapMonQtyFloat:e):S(finalFightValue) :(originalFightValue) *(origMonNum);
  612. !!VR(ceiler:e):S999 :1000;
  613. !!VR(newAdvMapMonQtyFloat):+(ceiler);
  614. !!VR(newAdvMapMonQtyFloat)&(newAdvMapMonQtyFloat)>=(INT32_MAX):S(INT32_MAX);
  615. !!VR(newMonNum:y):S(newAdvMapMonQtyFloat);
  616.  
  617. !!if&(newMonNum)=0:;
  618. ; New number cannot reach zero
  619. !!VR(newMonNum):S1;
  620. !!el&(newMonNum)<0:;
  621. ; Handle integer overflow
  622. !!VR(newMonNum):S(INT32_MAX);
  623. !!en;
  624.  
  625. ; New number cannot be bigger, than original one if neutrals have some possibility to grow during battle
  626. !!VR(newMonNum)&(newMonNum)>(origMonNum):S(origMonNum);
  627.  
  628. ; Call custom callback, allowing to change final neutral stack size on adventure map
  629. ; Here custom rules may be implement, for intstance, restoring neutrals if attacker escaped or died
  630. !!FU(mix_OnApplyNeutralsCasualities):P?(newMonNum)/(origMonNum)/i^mix_battleX^/i^mix_battleY^/i^mix_battleZ^;;
  631.  
  632. ; Overwrite neutrals final army
  633. !!re i/0/(MIX_MAX_NEUTRAL_STACKS)/1/-1:;
  634. !!BA:M(BATTLE_RIGHT)/i/(NO_MON)/0;
  635. !!en:;
  636.  
  637. !!BA:M(BATTLE_RIGHT)/0/(origMonType)/(newMonNum);
  638.  
  639. !?FU(mix_GetAdvMapMonInfo);
  640. ; Given coordinates of monster on adventure map, returns monster type and number.
  641. ; If object is not a monster, (NO_MON) type is returned.
  642. !#VA(x:x) (y:x) (z:x);
  643. !#VA(monType:x); OUT, (NO_MON) on error
  644. !#VA(monNum:x); OUT
  645. !!VR(monType):S(NO_MON);
  646. !!VR(monNum):S0;
  647. !!OB(x)/(y)/(z):T?(objType:y) U?(monType);
  648.  
  649. !!if&(objType)<>(OBJ_MONSTER):;
  650. !!VR(monType):S-1;
  651. !!FU:E;
  652. !!en:;
  653.  
  654. !!MO(x)/(y)/(z):G?(monNum);
  655.  
  656. !?FU(mix_ClearTileNeutralsConfig);
  657. !#VA(x:x) (y:x) (z:x);
  658. !!VR(configKey:z):S^mix_mon_%(x)_%(y)_%(z)^;
  659. !!SN:W(configKey)/?(config:y);
  660. !!SN&(config)<>0:M(config) W(configKey)/0;
  661.  
  662. !?FU(mix_GetTileNeutralsConfig);
  663. !#VA(x:x) (y:x) (z:x) (result:x) (autocreate:x) = (FALSE);
  664. ; Returns TNeutralsConfig: existing config for given map tile in the form of SN:M array ID or 0 if config is missing.
  665. ; Specify (autocreate) = (TRUE) to create new config, if nothing is found.
  666. ; Warning: calling any Mixed Neutrals API may invalid the result array ID.
  667. !!VR(configKey:z):S^mix_mon_%(x)_%(y)_%(z)^;
  668. !!SN:W(configKey)/?(result);
  669.  
  670. ; No config found, autocreate empty
  671. !!SN&(result)=0/(autocreate)<>(FALSE):M(M_AUTO_ID)/(MIX_NEUTRALS_CONFIG_SIZE)/(M_INT)/(M_STORED)/?(result)
  672. W(configKey)/(result)
  673. V(result)/0/(NO_MON)/0/(NO_MON)/0/(NO_MON)/0/(NO_MON)/0/(NO_MON)/0/(NO_MON)/0/(NO_MON)/0
  674. V(result)/(MIX_NEUTRALS_CONFIG_SPREAD_MASK_IND)/0;
  675.  
  676. !?FU(mix_ReadTileNeutrals);
  677. ; Calculates neutrals types and current final quantitites, writing them to user-specified array.
  678. ; The result contains virtual slots, which may be empty and non-sequential.
  679. !#VA(x:x) (y:x) (z:x);
  680. !#VA(neutrals:x); T Neutrals. SN:M array ID to write finally calculated data to.
  681. !#VA(success:x); Boolean. Optional, OUT. True, if data exists and was successfully read.
  682. !#VA(leftFightValue:x); Float. Optional, OUT. Not used Fight Value, that should be preserved after battle.
  683.  
  684. !!VR(success):S(FALSE);
  685.  
  686. ; Get config, exit if none
  687. !!FU(mix_GetTileNeutralsConfig):P(x)/(y)/(z)/?(config:y);
  688. !!FU&(config)=(FALSE):E;
  689.  
  690. ; Get total number of original creatures
  691. !!FU(mix_GetAdvMapMonInfo):P(x)/(y)/(z)/?(origMonType:y)/?(totalMons:y);
  692. !!FU|(origMonType)=(NO_MON)/(totalMons)<=0:E;
  693.  
  694. ; Calculate total fight value as float
  695. !!MA:F(origMonType)/?(origMonFightValue:y);
  696. !!VR(totalFightValue:e):S(totalMons) *(origMonFightValue);
  697. !!FU&(totalFightValue)<=0:E;
  698.  
  699. ; Initialize result to empty slots
  700. !!SN:V(neutrals)/0/-1/0/-1/0/-1/0/-1/0/-1/0/-1/0/-1/0;
  701.  
  702. ; Copy spread mask to result
  703. !!SN:V(config)/(MIX_NEUTRALS_CONFIG_SPREAD_MASK_IND)/?(spreadMask:y);
  704. !!SN:V(config)/(MIX_NEUTRALS_STRUCT_SPREAD_MASK_IND)/(spreadMask);
  705.  
  706. ; Unpack spread mask
  707. !#VA(spreads[7]:y);
  708. !!VR(spreads):C(FALSE)/(FALSE)/(FALSE)/(FALSE)/(FALSE)/(FALSE)/(FALSE);
  709.  
  710. !!re i/(@spreads[0])/(@spreads[-1]):;
  711. !!VR(spreadInd:y):Si -(@spreads);
  712. !!VR(testBit:y):S1 Sd<<(spreadInd) &(spreadMask);
  713. !!VRyi&(testBit)<>0:S(TRUE);
  714. !!en:;
  715.  
  716. ; Calculate each stack size in floats
  717. !!VR(numStacksToSpread:y):S0;
  718.  
  719. !!re i/0/(MIX_MAX_NEUTRAL_STACKS)/1/-1:;
  720. ; Skip free slot
  721. !!VR(pairInd:y):Si *2;
  722. !!SN:V(config)/(pairInd)/?(monType:y)/?(monRelQuantity:e);
  723. !!co&(monType)<=(NO_MON):;
  724.  
  725. ; Skip slot with zero fight value or quantity
  726. !!MA:F(monType)/?(monFightValue:y);
  727. !!VR(monQuantityFloat:e):S(totalFightValue) *(monRelQuantity) :(monFightValue);
  728. !!co&(monQuantityFloat)<=0:;
  729.  
  730. ; Force integer cap for number of creatures
  731. !!VR(monQuantityFloat)&(monQuantityFloat)>=(INT32_MAX):S(INT32_MAX);
  732.  
  733. ; Adjust number of stacks to spread
  734. !!VR(spread:y):S(@spreads) +i Sy(spread);
  735. !!VR(numStacksToSpread)&(spread)=(TRUE):+1;
  736.  
  737. ; Save monster in the result list
  738. !!SN:V(neutrals)/(pairInd)/(monType)/(monQuantityFloat);
  739. !!en:;
  740.  
  741. ; Determine free slot indexes and count
  742. !#VA(freeSlots[7]:y);
  743. !!VR(freeSlotPtr:y):S(@freeSlots);
  744.  
  745. !!re i/0/(MIX_MAX_NEUTRAL_STACKS)/1/-1:;
  746. !!VR(pairInd:y):Si *2;
  747. !!SN:V(neutrals)/(pairInd)/?(monType:y);
  748.  
  749. !!if&(monType)=(NO_MON):;
  750. !!VRy(freeSlotPtr):Si;
  751. !!VR(freeSlotPtr):+1;
  752. !!en;
  753. !!en:;
  754.  
  755. !!VR(numFreeSlots:y):S(freeSlotPtr) -(@freeSlots);
  756.  
  757. ; Apply spreading
  758. !!if&(numFreeSlots)>0/(numStacksToSpread)>0:;
  759. !!VR(slotsPerSpreadedStack:y):S(numFreeSlots) :(numStacksToSpread);
  760. !!VR(freeSlotsReserve:y):S(numFreeSlots) %(numStacksToSpread);
  761.  
  762. !!re i/0/(MIX_MAX_NEUTRAL_STACKS)/1/-1:;
  763. ; Continue if slot is free
  764. !!VR(pairInd:y):Si *2;
  765. !!SN:V(neutrals)/(pairInd)/?(monType:y)/?(monQuantityFloat:e);
  766. !!co&(monType)=(NO_MON):;
  767.  
  768. ; Continue if slot must not be spreaded
  769. !!VR(spread:y):S(@spreads) +i Sy(spread);
  770. !!co&(spread)<>(TRUE):;
  771.  
  772. ; Determine, how many free slots will be used for current stack
  773. !!VR(numOccupiedSlots:y):S(slotsPerSpreadedStack);
  774.  
  775. !!if&(freeSlotsReserve)>0:;
  776. !!VR(freeSlotsReserve):-1;
  777. !!VR(numOccupiedSlots):+1;
  778. !!en;
  779.  
  780. !!co&(numOccupiedSlots)<=0:;
  781.  
  782. ; Calculate float quantity for each slot to occupy
  783. !!VR(numStackSlots:y):S(numOccupiedSlots) +1;
  784. !!VR(spreadedMonQuantityFloat:e):S(monQuantityFloat) :(numStackSlots);
  785.  
  786. ; Update float monster quantity in main stack slot
  787. !!SN:V(neutrals)/(pairInd)/?t/(spreadedMonQuantityFloat);
  788.  
  789. ; Occupy new slots
  790. !!re j/0/(numOccupiedSlots)/1/-1:;
  791. !!VR(freeSlot:y):S(@freeSlots) +j Sy(freeSlot);
  792. !!VR(pairInd:y):S(freeSlot) *2;
  793. !!SN:V(neutrals)/(pairInd)/(monType)/(spreadedMonQuantityFloat);
  794. !!en:; re
  795. !!en:; re
  796. !!en; if
  797.  
  798. ; Apply merging in order to obtain integer non-zero quantities for each slot and unused fight value sum
  799. !#VA(monReserve[14]:y); array 7 of (monType: int, monQuantity: float)
  800. !!VR(monReserveSize:y):S0;
  801.  
  802. !!VR(numRealSlots:y):S0;
  803.  
  804. !!VRi:S(MIX_MAX_NEUTRAL_STACKS) -1;
  805.  
  806. ; Process each stack from right to left
  807. !!re i/i/0/-1:;
  808. ; Continue if slot is free
  809. !!VR(pairInd:y):Si *2;
  810. !!SN:V(neutrals)/(pairInd)/?(monType:y)/?(monQuantityFloat:e) V(neutrals)/(pairInd)/(NO_MON)/0;
  811. !!co&(monType)=(NO_MON):;
  812.  
  813. ; Search for the same monster type in reserve
  814. !!re (monReserveInd:y)/0/(monReserveSize)/1/-1:;
  815. !!VR(monReservePtr:y):S(monReserveInd) *2 +(@monReserve);
  816. !!VRy(monReservePtr):C?(reserveMonType:y)/?(reserveMonQuantity:e);
  817. !!br&(reserveMonType)=(monType):;
  818. !!en:;
  819.  
  820. ; Add monster from reserve to current stack, if any
  821. ; Create new reserve if current monster type is absent
  822. !!if&(monReserveInd)<(monReserveSize):;
  823. !!VR(monQuantityFloat):+(reserveMonQuantity);
  824. !!el:;
  825. !!VR(monReservePtr):S(monReserveSize) *2 +(@monReserve);
  826. !!VR(monReserveSize):+1;
  827. !!en;
  828.  
  829. ; Convert current stack quantity to integer
  830. !!VR(monQuantity:y):S(monQuantityFloat);
  831. !!VR(monQuantity)&(monQuantity)<0:S(INT32_MAX);
  832.  
  833. ; Calculate rest monster quantity for reserve
  834. !!VR(reserveMonQuantity:e):S(monQuantityFloat) -(monQuantity);
  835.  
  836. ; Update reserve
  837. !!VRy(monReservePtr):C(monType)/(reserveMonQuantity);
  838.  
  839. ; Update result stack
  840. !!VR(monType)&(monQuantity)=0:S(NO_MON);
  841. !!SN:V(neutrals)/(pairInd)/(monType)/(monQuantity);
  842. !!en:; re
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement