Drakous79 Posted November 29, 2012 Share Posted November 29, 2012 Haven't find it. Only in those unused constants. Link to comment Share on other sites More sharing options...
DaGawdfadda Posted December 1, 2012 Share Posted December 1, 2012 (edited) What exactly are you trying to change about cover? there are skills to improve defense and cover..with more information i may could help. Some folks feel that if a soldier is in full cover and hunkered he should be 100% (or close to) safe unless he is flanked and vice versa for the aliens. Right now thats not the case. I play my games moving my soldiers exclusivly to high cover so that I avoid taking damage but I still get hit from offscreen or across insane distances. My only option is basically to savescum. The other is to use one soldier to pull aliens into killing zones which becomes really effective once you get high end snipers but still feels like cheating and is completly counter to the supposed tactical game where we are supposed to flank and overwatch. The ideal game was Full Spectrum Warrior. If you were in cover and your enemy was in cover no matter how much lead was put down range neither side took damage (unless the cover was destroyable) and you had to flank or use special abilities to take out your target. This should be the case with xcom. If you are out in the open one hit=one kill (with exceptions for high end armour and aliens like mutons) half cover no hunker= small chance of being killed or damaged (you expose yourself when firing but its so short that it would have to be a perfect shot)half cover and hunker/full cover no hunker= small chance of taking minor damage (the cover hides your head/torso but your limbs can still be hit/ your arms/legs are exposed as you are firing but again require a perfect shot)full cover hunker (you are completly hidden from the enemy and short of taking out the cover you cant be hit by anything) That was at least my initial interest in modding cover but i have no really knowledge in this area and was simply bringing the idea up so people who could take a look might. Not sure if others who are interested feel the same way so hopefully if they disagree with me they'll post an answer for you. Edited December 1, 2012 by DaGawdfadda Link to comment Share on other sites More sharing options...
Just6669 Posted December 1, 2012 Share Posted December 1, 2012 I spend several hours looking for functions using cover values to modify hit chances in hope to find where exactly are these values defined. Code was (purposely?) made mess, some crucial functions and classes properties etc have "dynamic" names, that are only uses locally. Then there are replication functions, that I do not fully understand, they seem to propagate some properties (maybe functions too) "outside" of the class, but not always under same name. So, even if you find where cover values are set, or read, there will be NO reference to such variable/function name in any other class. This could be "replicated" under another name, or sometimes there are arrays of variables and code is looking by index number, without referencing to specific name.They are also function names or variables inherited while calling from another class, again makes back-tracing a road through hell. Some examples what we have to deal with: I started looking for for function, that generates hit or miss (true/false) while shooting.Found it in classXGAbility_Targetedfunction RollForHit() function RollForHit() { local float fRoll, fChance, fDist, fScatter; local int iAdjustedChance, iRoll; local XGAction_Fire kFireAction; local XGParamTag kTag; local Vector VDir, vDest; local Rotator rRotate; local XComUIBroadcastWorldMessage kBroadcastWorldMessage; kTag = XGParamTag(XComEngine(class'Engine'.static.GetEngine()).LocalizeContext.FindTag("XGParam")); m_bHit = false; kFireAction = XGAction_Fire(m_kUnit.GetAction()); (...) Code is long, there are some checks for "special" attacks, like rocket or psi, or debug cheat values (deadeye = always hit, noluck = always miss").In the end, what this function does for standard shot is:-calculate adjusted shot percentage and converting it to float 0..1: iAdjustedChance = AdjustToHit(GetHitChance()); fChance = float(iAdjustedChance) / 100.00; And now, setting hit to true/false: m_bHit = XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.RollForHit(fChance, m_kUnit.GetCharacter().m_kChar, GetPrimaryTarget().GetCharacter().m_kChar, fRoll); ...??? What is this ? These four parameters are probably (hit chanse, attacker, target, ??? ). OK, did not go so well. so let us check function AdjustToHit. Maybe there are cover adjustments. XGAbility_Targetedfunction int AdjustToHit(int iHitChance) function int AdjustToHit(int iHitChance) { local int iMissAdjustment, iAdjustment, iAdjustedHitChance; local XGPlayer kPlayer; (...) Again, we have some checks for specials. No cover, perks & abilities only, so I do not paste this function here, if you want more, look at it in UE Explorer.You can for example find, that difficulty leave is directly used to influence hit chances, and that there are friendly fire checks in the code. OK, we go back. We had: "iAdjustedChance = AdjustToHit(GetHitChance()); " GetHitChance() look interesting. It is used as base hit chance parameter, in another function call. Searching...XGAbility_Targeted simulated function int GetHitChance() { return m_iHitChance; } Simulated. Don't really remember what it means, I guess that just returns m_iHitChance as value. So, m_iHitChance must be set somewhere else.The only point where it is calculated is: XGAbilityTree kAbility.m_iHitChance = kAbility.CalcHitChance(); Looking for CalcHitChance in classes...XGAbility_Targeted native function int CalcHitChance(); Function is there, but it is empty. No other definition in other classes, it is being called several times, but no trace of actually calculating its value. That is it. I'm done. Lost many hours of life (what you see is only one of several paths through code I made).They all ended up with some nonsense (empty) function where the was supposed to be a crucial calculation. It was about fifteen years since I did things like this (yes, I'm so old), do not be to harsh if I wrote some nonsense. or made mistakes. I expect someone makes better work then I did. Link to comment Share on other sites More sharing options...
Drakous79 Posted December 1, 2012 Share Posted December 1, 2012 (edited) UnrealScript Functions at http://udn.epicgames.com SimulatedDeclares that a function may execute on the client-side when an actor is either a simulated proxy or an autonomous proxy. All native functions are automatically simulated as well. (Note: if you override a virtual native with a non-native function' date=' the non-native override will NOT be simulated unless this keyword is specified).[/indent']NativeYou can declare UnrealScript functions as native, which means that the function is callable from UnrealScript, but is actually implemented (elsewhere) in C++. For example, the Actor class contains a lot of native function definitions, such as:native(266) final function bool Move( vector Delta );The number inside the parenthesis after the native keyword corresponds to the number of the function as it was declared in C++ (using the AUTOREGISTER_NATIVE macro), and is only required for operator functions. The native function is expected to reside in the DLL named identically to the package of the class containing the UnrealScript definition.Well, there is no XComGame.dll, but maybe it is in thegame's executable. Also UE Explorer 1.2 shows:// Export UXGAbility_Targeted::execCalcHitChance(FFrame&, void* const) native function int CalcHitChance(); Many searches end with native functions. Hope we will be able to see what are they doing one day. Edited December 1, 2012 by Drakous79 Link to comment Share on other sites More sharing options...
Just6669 Posted December 1, 2012 Share Posted December 1, 2012 (edited) Thanks for tips. It is my first contact with UE, I only wrote some simple software in C++ years ago. Anyway, by looking in code you can easily see, that lot of constants were changed to numbers before retail exe was compiled. Like here:XGAbility_Targeted.h coverPerks = kTarget.GetTacticalSenseCoverBonus(); // End:0x211 if(kTarget.HasBonus(15) && kTarget.HasHeightAdvantageOver(m_kUnit)) { coverPerks += XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.10; //high advantage defense bonus = 10 } // End:0x29e if(kTarget.m_bInSmokeBomb) { coverPerks += XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.20; //smoke bomb defense bonus = 20 } // End:0x32b if(kTarget.m_bInDenseSmoke) { coverPerks += XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.20; //dense smoke defense bonus = 20 } coverBonus = Max(0, kTarget.m_iCurrentCoverValue - coverPerks); // End:0x3ed if(kTarget.HasAirEvadeBonus()) { iEvasionBonus = XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.20; //air evade defense bonus = 20 } coverBonus = Max(0, coverBonus - iEvasionBonus); or here : if(coverBonus != 0 && !m_bHasFlank) { // End:0x817 if(coverBonus == XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.20) // compares cover bonus DIRECTLY to 20 ! { kInfo.arrHitPenaltyStrings.AddItem(m_strPenaltyLowCover); } // End:0x840 else { kInfo.arrHitPenaltyStrings.AddItem(m_strPenaltyHighCover); } kInfo.arrHitPenaltyValues.AddItem(-coverBonus); // End:0x948 if(kTarget.IsAffectedByAbility(38)) { kInfo.arrHitPenaltyStrings.AddItem(m_strHunker); kInfo.arrHitPenaltyValues.AddItem(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.2 - 1 * -coverBonus); // "1 *" means hunker down cover bonus = base cover bonus. (they stack). } } Not really modding friendly way to compile. BTW I thought about making hunker down check always true to make cover twice effective. Or, sacrifice "Dense smoke" perk to make both cover values +20 by changing it's check to : if(kTarget.IsInCover()) { coverPerks += XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.20; //dense smoke defense bonus is now always applied when in cover } Could anyone try to make such changes ? I'm not sure if I can. EDIT: I think it would not work anyway, this function is probably only to generate values to display on UI target info screen. Edited December 1, 2012 by Just6669 Link to comment Share on other sites More sharing options...
Drakous79 Posted December 1, 2012 Share Posted December 1, 2012 (edited) Dense smoke - you are genius :) Not sure, if we can replace a string with a function. Hope we can! Edit: Ah I see, it is kTarget. My eyes need rest. Edited December 1, 2012 by Drakous79 Link to comment Share on other sites More sharing options...
Just6669 Posted December 1, 2012 Share Posted December 1, 2012 I went through classes again. I think I understand cover logic pretty well, unfortunately crucial functions like: // Export UXGUnitNativeBase::execSetCoverValue(FFrame&, void* const) native simulated function SetCoverValue(int iNewCoverValue); // Export UXGUnitNativeBase::execGetTacticalSenseCoverBonus(FFrame&, void* const) native simulated function int GetTacticalSenseCoverBonus(); // Export UXGUnitNativeBase::execGetLowProfileCoverBonus(FFrame&, void* const) native simulated function int GetLowProfileCoverBonus(); are virtual, so unit cover values are set from "outside" of what we can now change. Dead end. But.I think we can adjust hit chance "manually", because function bool RollForHit(float fChance, out TCharacter kShooter, out TCharacter kTarget, out float fRoll) { fRoll = class'XComEngine'.static.SyncFRand(string(Name) @ string(GetStateName()) @ string(GetFuncName())); return fRoll <= fChance; } Is not native and all we have to do is adjust local fChance parameter to increase cover influence somewhere before this call: m_bHit = XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.RollForHit(fChance, m_kUnit.GetCharacter().m_kChar, GetPrimaryTarget().GetCharacter().m_kChar, fRoll); Function returning hit or miss itself is again in not accessible class 'Engine', but parameter fChance is local, and it is adjusted just a few lines above: if(XComTacticalCheatManager(GetALocalPlayerController().CheatManager).bDeadEye) { fChance = 1.0; } // End:0xc31 else { // End:0xbf7 if(XComTacticalCheatManager(GetALocalPlayerController().CheatManager).bNoLuck) { fChance = 0.0; } // End:0xc31 else { iAdjustedChance = AdjustToHit(GetHitChance()); fChance = float(iAdjustedChance) / 100.0; } } m_bHit = XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.RollForHit(fChance, m_kUnit.GetCharacter().m_kChar, GetPrimaryTarget().GetCharacter().m_kChar, fRoll); // End:0x131a You can see two checks, that we could use to make our change. They are normally used to force hit or miss by internal game cheat manager. This also suggests, that locally changing exit value will not crash the game, yes there are several checks in code, but in a local (network == 0) game all they do is activating cheated flag / string (to debug log?). So, is anyone able to change these DeadEye and NoLuck checks to something, that will useGetPrimaryTarget().XComGame.GetTacticalSenseCoverBonus() (will be 20 or 40) to reduce fchance? maybe sth like this: if (GetPrimaryTarget().XComGame.GetTacticalSenseCoverBonus == 20) { fChance = 0.8 * fChance // decreases hit change by another 20% if low cover } else { if (GetPrimaryTarget().XComGame.GetTacticalSenseCoverBonus == 40) { fChance = 0.7 * fChance // decreases hit change by another 30% if high cover } } This adjusting would stack with default bonuses. Is it doable ? Link to comment Share on other sites More sharing options...
dreadylein Posted December 1, 2012 Share Posted December 1, 2012 nativ functions arent empty, they just arent coded in the ue code But you already got everthing you need, you know how the functions are called and what is expected to return from them Fire up the binary in your favorite debugger or dissambler and look for the functions, you should find anything you needIf the coverchances are hardcoded it should be easy to mod it Link to comment Share on other sites More sharing options...
Just6669 Posted December 1, 2012 Share Posted December 1, 2012 (edited) Code fragments, which I pasted here, with numbers, are not used to calculate hit chance nor cover bonus. They are just used to compare read cover value with hardcoded number, to generate UI (and debug?) text strings. Cover bonus values (probably array of 4 integers, for every direction) are is probably set in: // Export UXGUnitNativeBase::execSetCoverValue(FFrame&, void* const) native simulated function SetCoverValue(int iNewCoverValue); To find which cover value should be used for specified shot, game uses xxx.XComGame.GetTacticalSenseCoverBonus where xxx is any funtion/variable, that can define what actor is the target, for example GetPrimaryTarget().XComGame.GetTacticalSenseCoverBonus There are possibilities of multiple targets, that is why hit modifiers are used with such prefix. So, if I understand you correctly, function SetCoverValue should be in class XGUnitNativeBase, and I can search it by offset given by UE ? When I get home I will give it a try. Edited December 2, 2012 by Just6669 Link to comment Share on other sites More sharing options...
Just6669 Posted December 2, 2012 Share Posted December 2, 2012 So, here is the buffer of XComGame.XGUnitNativeBase.SetCoverValue Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 00000000 D1 33 00 00 47 55 00 00 00 00 00 00 CA 33 00 00 . 3 . . G U . . . . . . . 3 . . 00000010 00 00 00 00 00 00 00 00 CB 33 00 00 00 00 00 00 . . . . . . . . . 3 . . . . . . 00000020 3C 08 00 00 D1 3C 01 00 0B 00 00 00 07 00 00 00 < . . . . < . . . . . . . . . . 00000030 29 CB 33 00 00 0B 53 00 00 00 00 05 02 00 8B 61 ) . 3 . . . S . . . . . . . . a 00000040 00 00 00 00 00 00 . . . . . . After some "random clicking" I realized, that UE seems to recognize some "things".: D1 33 00 00 Obj XGUnitNativeBase.GetTacticalSenseCoverBonus.ReturnValueCA 33 00 00 Obj XGUnitNativeBase.CanUseCoverCB 33 00 00 Obj. XGUnitNativeBase.SetCoverValue.iNewCoverValue8B 61 00 00 Name. SetCoverValue How can I use the unidentified data to continue my hunt ? Link to comment Share on other sites More sharing options...
Recommended Posts