Skip to content

Commit

Permalink
feat(Era): Update Era source code to 3.9.10. Commit: 3c7f910
Browse files Browse the repository at this point in the history
Signed-off-by: VuceticBranislav <24853106+VuceticBranislav@users.noreply.github.com>
  • Loading branch information
VuceticBranislav committed Apr 17, 2024
1 parent 06a6eb8 commit e276749
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 11 deletions.
20 changes: 19 additions & 1 deletion Era/Heroes.pas
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,14 @@ TTextTable = class
IsTwoLevelMap: boolean;
end; // .record TGameManager

PBattleStack = ^TBattleStack;
TBattleStack = packed record
Unk1: array [0..$34 - 1] of byte;
MonType: integer; // +0x34
Pos: integer; // +0x38
Unk2: array [$3C..$548 - 1] of byte;
end; // .record TBattleStack

PPCombatManager = ^PCombatManager;
PCombatManager = ^TCombatManager;
TCombatManager = packed record
Expand Down Expand Up @@ -1099,7 +1107,9 @@ TTextTable = class

// _Dlg_* dlg; // + 0x132FC
// _byte_ field_13300[3564];
end; // .TCombatManager

function GetActiveStack: PBattleStack;
end; // .record TCombatManager

PPAdvManager = ^PAdvManager;
PAdvManager = ^TAdvManager;
Expand Down Expand Up @@ -1363,6 +1373,14 @@ procedure TNetData.Send (aDestPlayerId: integer);
PatchApi.Call(FASTCALL_, Ptr($5549E0), [@Self, aDestPlayerId, 0, 1]);
end;

function TCombatManager.GetActiveStack: PBattleStack;
Type
TGetActiveStackMethod = function (CombatMgr: PCombatManager): PBattleStack; cdecl;

begin
result := TGetActiveStackMethod(Ptr($75AF06))(@Self);
end;

procedure SendNetData (DestPlayerId, MsgId: integer; {n} Data: pointer; DataSize: integer);
var
NetDataBuf: UtilsB2.TArrayOfByte;
Expand Down
75 changes: 66 additions & 9 deletions Era/Tweaks.pas
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ function RandomRangeWithFreeParam (MinValue, MaxValue, FreeParam: integer): inte
fRangeMax: integer;
fCombatActionId: integer;
fFreeParam: integer;
fAttemptParam: integer;
end;

TBattleDeterministicRng = class (FastRand.TRng)
Expand All @@ -106,7 +107,7 @@ TBattleDeterministicRng = class (FastRand.TRng)
fCombatActionIdPtr: pinteger;
fFreeParamPtr: pinteger;

procedure UpdateState (RangeMin, RangeMax: integer);
procedure UpdateState (RangeMin, RangeMax: integer; AttemptIndex: integer = 1);

public
constructor Create (CombatIdPtr, CombatRoundPtr, CombatActionIdPtr, FreeParamPtr: pinteger);
Expand Down Expand Up @@ -167,14 +168,15 @@ constructor TBattleDeterministicRng.Create (CombatIdPtr, CombatRoundPtr, CombatA
Self.fFreeParamPtr := FreeParamPtr;
end;

procedure TBattleDeterministicRng.UpdateState (RangeMin, RangeMax: integer);
procedure TBattleDeterministicRng.UpdateState (RangeMin, RangeMax: integer; AttemptIndex: integer = 1);
begin
Self.fState.fCombatRound := Crypto.Tm32Encode(Self.fCombatRoundPtr^);
Self.fState.fRangeMin := RangeMin;
Self.fState.fCombatId := Crypto.Tm32Encode(Self.fCombatIdPtr^);
Self.fState.fRangeMax := RangeMax;
Self.fState.fCombatActionId := Crypto.Tm32Encode(Self.fCombatActionIdPtr^ + 1147022261);
Self.fState.fFreeParam := Crypto.Tm32Encode(Self.fFreeParamPtr^ + 641013956);
Self.fState.fAttemptParam := 1709573561 + AttemptIndex * 39437491;
end;

procedure TBattleDeterministicRng.Seed (NewSeed: integer);
Expand All @@ -189,6 +191,15 @@ function TBattleDeterministicRng.Random: integer;
end;

function TBattleDeterministicRng.RandomRange (MinValue, MaxValue: integer): integer;
const
MAX_UNBIAS_ATTEMPTS = 100;

var
RangeLen: cardinal;
BiasedRangeLen: cardinal;
MaxUnbiasedValue: cardinal;
i: integer;

begin
if MinValue >= MaxValue then begin
result := MinValue;
Expand All @@ -199,7 +210,23 @@ function TBattleDeterministicRng.RandomRange (MinValue, MaxValue: integer): inte
result := Crypto.FastHash(@Self.fState, sizeof(Self.fState));

if (MinValue > Low(integer)) or (MaxValue < High(integer)) then begin
result := MinValue + integer(cardinal(result) mod cardinal(MaxValue - MinValue + 1));
i := 2;
RangeLen := cardinal(MaxValue - MinValue) + 1;
BiasedRangeLen := High(cardinal) mod RangeLen + 1;

if BiasedRangeLen = RangeLen then begin
BiasedRangeLen := 0;
end;

MaxUnbiasedValue := High(cardinal) - BiasedRangeLen;

while (cardinal(result) > MaxUnbiasedValue) and (i <= MAX_UNBIAS_ATTEMPTS) do begin
Inc(Self.fState.fAttemptParam, 39437491);
result := Crypto.FastHash(@Self.fState, sizeof(Self.fState));
Inc(i);
end;

result := MinValue + integer(cardinal(result) mod RangeLen);
end;
end;

Expand Down Expand Up @@ -860,6 +887,8 @@ function Hook_WoGBeforeBattleAction (Context: Core.PHookContext): longbool; stdc
BattleMgr: Heroes.PCombatManager;

begin
Inc(CombatActionId);

BattleMgr := Heroes.CombatManagerPtr^;

CombatOrigStackActionInfo.Action := BattleMgr.Action;
Expand All @@ -870,6 +899,33 @@ function Hook_WoGBeforeBattleAction (Context: Core.PHookContext): longbool; stdc
result := Core.EXEC_DEF_CODE;
end;

function Hook_WoGBeforeBattleAction_HandleEnchantress (Context: Core.PHookContext): longbool; stdcall;
const
LOCAL_ACTING_MON_TYPE = -$2C;

var
BattleMgr: Heroes.PCombatManager;

begin
BattleMgr := Heroes.CombatManagerPtr^;
Erm.v[997] := CombatRound;
Erm.FireErmEvent(TRIGGER_BG0);

// Monster type could be changed by script, use the one from combat manager
pinteger(Context.EBP + LOCAL_ACTING_MON_TYPE)^ := BattleMgr.GetActiveStack().MonType;

result := Core.EXEC_DEF_CODE;
end;

function Hook_WoGCallAfterBattleAction (Context: Core.PHookContext): longbool; stdcall;
begin
Erm.v[997] := CombatRound;
Erm.FireErmEvent(TRIGGER_BG1);

Context.RetAddr := Ptr($75D317);
result := not Core.EXEC_DEF_CODE;
end;

function Hook_SendBattleAction_CopyActionParams (Context: Core.PHookContext): longbool; stdcall;
begin
Context.EAX := CombatOrigStackActionInfo.ActionParam2;
Expand Down Expand Up @@ -935,11 +991,6 @@ function Hook_OnCombatRound_End (Context: Core.PHookContext): longbool; stdcall;
var
RngId: integer = 0; // Holds random generation attempt ID, auto resets at each reseeding. Used for debugging purposes

procedure OnBeforeBattleAction (Event: GameExt.PEvent); stdcall;
begin
Inc(CombatActionId);
end;

procedure Hook_SRand (OrigFunc: pointer; Seed: integer); stdcall;
var
CallerAddr: pointer;
Expand Down Expand Up @@ -2139,6 +2190,13 @@ procedure OnAfterWoG (Event: GameExt.PEvent); stdcall;
ApiJack.HookCode(Ptr($75C69E), @Hook_WoGBeforeBattleAction);
ApiJack.HookCode(Ptr($47883B), @Hook_SendBattleAction_CopyActionParams);

(* Trigger OnBeforeBattleAction before Enchantress, Hell Steed and creature experience mass spell processing *)
ApiJack.HookCode(Ptr($75C96C), @Hook_WoGBeforeBattleAction_HandleEnchantress);
Core.p.WriteDataPatch(Ptr($75CB26), [myAStr('9090909090909090909090')]);

(* Use CombatRound in OnAfterBattleAction trigger for v997 *)
ApiJack.HookCode(Ptr($75D306), @Hook_WoGCallAfterBattleAction);

(* Send and receive unique identifier for each battle to use in deterministic PRNG in multiplayer *)
ApiJack.HookCode(Ptr($763796), @Hook_ZvsAdd2Send);
ApiJack.HookCode(Ptr($763BA4), @Hook_ZvsGet4Receive);
Expand Down Expand Up @@ -2202,7 +2260,6 @@ procedure OnAfterVfsInit (Event: GameExt.PEvent); stdcall;
EventMan.GetInstance.On('OnAfterVfsInit', OnAfterVfsInit);
EventMan.GetInstance.On('OnAfterWoG', OnAfterWoG);
EventMan.GetInstance.On('OnBattleReplay', OnBattleReplay);
EventMan.GetInstance.On('OnBeforeBattleAction', OnBeforeBattleAction);
EventMan.GetInstance.On('OnBeforeBattleReplay', OnBeforeBattleReplay);
EventMan.GetInstance.On('OnBeforeBattleUniversal', OnBeforeBattleUniversal);
EventMan.GetInstance.On('OnGenerateDebugInfo', OnGenerateDebugInfo);
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
Contains ERA and VFS projects as well as B2 library.<br/>
<br/></i>
Original commits containing code are from <a href="https://github.com/ethernidee">ethernidee</a> repositories:<br/>
ERA: <a href="https://github.com/ethernidee/era/tree/9ddfbbf2d1a59a87f8a80a468262878c3ecd0501"><strong>9ddfbbf</strong></a><br/>
ERA: <a href="https://github.com/ethernidee/era/tree/3c7f91013059e60603ac075d1105313d37a3b488"><strong>3c7f910</strong></a><br/>
VFS: <a href="https://github.com/ethernidee/vfs/tree/5e4a7f0acf1bdfa9eadb3f63c7177e8f0ccbf2e0"><strong>5e4a7f0</strong></a><br/>
B2: <a href="https://github.com/ethernidee/b2/tree/001251eb5f45378c329b6a60a4a4d87c346f36a0"><strong>001251e</strong></a>
</p>
Expand Down

0 comments on commit e276749

Please sign in to comment.