Code:
Version 3.9.3 (09/2022)
------------------------
[+] Rewrote game random number generator (RNG) engine.
Main changes:
- All RNGs are not thread safe now. They should be used in the main thread only.
- There are two main RNGs: the global one (rand/srand/VR:R) and the unique one (VR:T).
- ERA uses 3 different engines for the global RNG and switches them dynamically to provide qualitative outputs, the same battle obstacles, as they are in original Heroes 3, and network PvP battles stability.
- VR:T generator cannot be seeded anymore. It serves as the source of unpredictable randomness.
- At the start of game process, all generators are seeded with cryptographically safe random seeds.
- Most of the time Xoroshiro128** engine is used for global RNG. It has both excellent speed and qualitative output.
- The global generator engine is switched to native C rand implementation only for the phase of placing battle obstacles.
- In network PvP battles the global generator is switched to deterministic one. Deterministic generator uses only the following information: unique battle ID, combat round ID, combat action ID, minimum and maximum value to generate. Thus any attempt to generate a sequence of numbers in the same range will produce the same result for each generation. It's recommended to replace dwarf-style resistence mechanics with golem-style resistence mechanics.
- Global RNG is seeded with unique value at battle start/replay, thus the first action and autocasted spells are not deterministic anymore.
- Using random functions in before battle and before battlefield visible phases does not influence battle obstacles placing anymore.
- Extended "Debug.Rng" setting in "heroes 3.ini". 0 means no debugging, 1 is for seeding, 2 is for seeding and random_range, 3 enables debugging of all rand/srand/random_range calls.
- rand() is guaranteed to return 0..32767 value, as it does in original Heroes 3. But random_range (VR:R/VR:T) call can return any value in int32 range (-2147483648..2147483647).
- ERA intercepts all rand/srand calls. Previously a few functions were not tracked.
- Deterministic RNG for network PvP battles is enabled for the whole battle (excluding obstacles placing stage). Bad morale probability and magic resistence additionaly depend on stack ID, thus producing different results for different stacks. Stack damage calculation additionally depends on iteration counter (game generates up to 10 random values for each stack damage event).
[+] Added new event: "OnBeforePlaceBattleObstacles", occuring after "OnBeforeBattlefieldVisible" event. Global RNG is switched to the native one before calling ERM event and the generator is seeded with the following value: (110291 * map_tile_x + 167801 * map_tile_y + 81569). Thus the same obstacle types and positions are guaranteed for each particular map tile. Using RNG functions in this event will influence obstacles generation. Modder may implement unique obstacles for each battle at this phase or use custom deterministic seed formula.
[+] Added new event "OnAfterPlaceBattleObstacles", occuring after all obstacles are placed on battlefield. Random number generated is switched back to the qualitative one. New custom obstacles may be added in this phase.
[+] Implemented easy-to-use means to generate remote Era events with arbitrary data. The whole process of data compressing/decompressing/splitting/joining is hidden from clients. Support for progress callbacks is implemented. The following exported function was added to era.dll:
(* Generates remote Era event. Returns 1 if at least an attempt to call remote event was done. False for invalid/empty/too long event name *)
function FireRemoteNetworkEvent (
DestPlayerId: integer; // Destination player ID or -1 for all players
EventName: pchar; // Event name like "OnSomethingHappened"
{n} Data: pointer; // Pointer to buffer with data to send
DataSize: integer; // Size of the buffer with data
{n} ProgressHandler: TNetworkStreamProgressHandler; // Progress handler function or null
{n} ProgressHandlerCustomParam: pointer // Custom parameter for progress handler function
): TDwordBool; stdcall;
Big amounts of data are divided into smaller packets and sent one by one. In this case ProgressHandler function is called after successful packet sending, allowing to abort the stream or update interface. Small packets will be joined automatically on remote side and single event will be generated. Moreover, the data is sent in compressed form, increasing transferring speed. HD Mod Lobby is fully supported.
TNetworkStreamProgressHandler = function (BytesSent, TotalBytes: integer; {n} CustomParam: pointer): TDwordBool; stdcall;
[+] Erm "FU:D" command was fully rewritten. Fixed bug: HD mod used to disable FU:D on adventure map. From now FU:D supports arbitrary string parameters and d-modifiers.
[+] Map editor uses "*.msk" files instead of "*.msg" files now.
[+] ERA will retrieve final addresses to monster, spell, artifact and skill structures in OnAfterStructRelocations event using native pointers to those structures. Credits: Xeromant.
[-] Fixed issues with HD-mod way of loading game from battle. OnGameEnter/OnGameLeave counter will
not be corrupted if HD mod generates "$OnGameLeave" event for ERA before quitting game loop.
Version 3.9.2 (12/2021)
------------------------
[+] Implemented palette colorization support for def png frames.
The rules are the same, as for pcx png replacements. Png file should either use special 32 reserved colors or there should exist alternative png file named "groupInd_frameInd_p[player index].png". Example: "dialgbox.def/0_0_p3.png". Alternative files are not used if single png frame redirection is used.
[+] Added new "OnAfterBuildTownBuilding" event, occuring right after town building was built.
x-parameters: Town ID, Building ID.
[+] Added new "OnKeyReleased" event, occuring on keyboard key release.
Parameters: keyCode, preventDefault.
Example:
!?FU(OnKeyReleased);
!#VA(key:x) (preventDefault:x);
!!IF:M^Released key %(key)^;
[+] Added new events to Era Erm Framework: "OnKeyReleased_AdvMap", "OnKeyReleased_Battle", "OnKeyReleased_HeroScreen",
"OnKeyReleased_HeroMeetingScreen", "OnKeyReleased_Town", occuring right after "OnKeyReleased" events and taking two arguments:
x1 - key code
x2 - prevent default reaction (0 - no, 1 - yes).
Example:
!?FU(OnKeyReleased_Battle)&x1=(KEY_F1):;
!#VA(key:x) (preventDefault:x);
!!VR(preventDefault):S(TRUE);
!!IF:M^Released F1 in battle!^;
[+] Added the following functions to Era Erm Framework:
!?FU(H3Dlg_GetCurrentDlgId);
; Returns topmost dialog unique ID (DLG_XXX constant). It may be message box, custom dialog or any in-game dialog.
!#VA(result:x);
!?FU(AddArtToHero);
; Adds artifact to hero, trying to equip it first and fallbacking to putting in backpack. Returns success flag.
; Automatically builds combo arts and checks scenario win conditions.
!#VA(hero:x); ID of hero to equip artifact to.
!#VA(art:x); ID of artifact to equip.
!#VA(artMod:x); Artifact modifier or (NO_ART_MOD). For spell scrolls its spell ID. For other artifacts the value is usually ignored.
; Custom artifact modifiers may be implemented. Artifact modifier is always carried with artifact by game functions.
!#VA(result:x); Boolean. Success flag.
!?FU(GetArtAtSlot);
; Returns hero artifact and artifact modifier at given slot.
!#VA(hero:x); Hero ID or (CURRENT_HERO)
!#VA(slot:x); Slot ID (backpack is supported).
!#VA(artId:x); OUT. Artifact ID.
!#VA(artMod:x); OUT. Artifact modifier.
!?FU(ChangeArtModAtSlot);
; Changes artifact modifier in specified hero slot. Usually modifier is spell ID for spell scrolls or (NO_ART_MOD).
!#VA(hero:x); Hero ID or (CURRENT_HERO)
!#VA(slot:x); Slot ID (backpack is supported).
!#VA(artMod:x); Artifact modifier.
[+] The following functions were changed in Era Erm Framework:
!?FU(EquipArtToSlot);
; Tries to put artifact to specified hero doll slot, triggering OnEquipArt event. Returns success flag.
!#VA(hero:x); ID of hero to equip artifact to.
!#VA(art:x); ID of artifact to equipt.
!#VA(artMod:x); Artifact modifier or (NO_ART_MOD). For spell scrolls it's spell ID. For other artifacts the value is usually ignored.
; Custom artifact modifiers may be implemented. Artifact modifier is always carried with artifact by game functions.
!#VA(slot:x); ID of hero doll slot to put artifact in or (NO_ART_SLOT) for autodetection.
!#VA(result:x); Boolean. Success flag.
!?FU(GetHeroPrimarySkillsWithoutArts);
; ...
The function correctly handles artifact modifiers now, including spell IDs of magic scrolls.
[+] Added KEY_ENTER constant to Era Erm Framework, as alias to KEY_RETURN.
[+] Added new exported functions to era.dll:
- PcxPngExists (const PcxName: pchar): integer; stdcall;
Tries to load PNG replacement for pcx file name and returns success flag (0 or 1).
[+] Added support for LMB popup dialogs positioning at click coordinates.
[+] Included updated zutorial.tut file by Archer.
[-] Fixed crash in OnAICalcStackAttackEffect event, occuring on attempt to get tower stack ID by invalid position (251, 254, 255). Credits: daemon_n.
[-] Fixed bug: composite images with pcx16 background didn't use to respect pcx redirections.