The dnSpy code is functionally identical. Break just means "go to the end of the switch statement". Since the Any type does nothing, the end of the switch statement is immediately after Any. It's basically replacing the first two breaks with a jmp to the third break. Which is still a break. The code you posted is technically truer to the ASM structure, but they have the same meaning.fireundubh wrote: ↑Wed Oct 03, 2018 1:30 pmdnSpy doesn't get that switch statement right. With dotPeek, I see this:
You'll note that instead of breaking out of the switch, the Enemy and Ally cases just go to the Any case. This explains why m_TargetType gets set to 2. This also means that your CE patch might mean non-hostile area-of-effect spells/abilities won't work on party members.Code: Select all
case TargetType.Enemy: source = source.Where<UnitEntityData>(new Func<UnitEntityData, bool>(context.MaybeCaster.IsEnemy)); goto case TargetType.Any; case TargetType.Ally: source = source.Where<UnitEntityData>(new Func<UnitEntityData, bool>(context.MaybeCaster.IsAlly)); goto case TargetType.Any; case TargetType.Any: if (this.m_Condition.HasConditions) source = (IEnumerable<UnitEntityData>) source.Where<UnitEntityData>((Func<UnitEntityData, bool>) (u => { using (context.GetDataScope((TargetWrapper) u)) return this.m_Condition.Check((BlueprintScriptableObject) null); })).ToList<UnitEntityData>(); return source.Select<UnitEntityData, TargetWrapper>((Func<UnitEntityData, TargetWrapper>) (u => new TargetWrapper(u)));
You're welcome to view the ASM at any point. It first checks that the value isn't 3 or above (since there's no TargetType for that), then it shifts the targettype right three times (multiplying by 8), adds it to a "static" value (which is just after the function), then jumps to where that points, which is back inside the function. Essentially three pointers for each case. Me changing the value from 2 to 0 just means that it reduces the selection to just enemies of the caster, and then I add an extra check to make sure enemies can still friendly-fire eachother.
m_TargetType does not get changed anywhere in the code. There are different GetTargetType functions, but nothing modifies m_TargetType. Certainly nothing in this function's ASM does.
Code: Select all
code:
movsxd r14,dword ptr [r15+2C] // ORIGINAL CODE, r15 is the AbilityTargetsAround instance, [r15+2C] is this.m_TargetType
pushfq // Since we're gonna compare stuff, push flags to stack
push rbx // Same with our temp register (I like using rax and rbx for stuff)
cmp rcx,#0 // rcx is a pointer to context.MaybeCaster (presumably whoever cast the spell...)
je skip // null pointer check, just in case
mov rbx,[rcx+38] // context.MaybeCaster.m_Group
cmp [rbx+40],#1 // context.MaybeCaster.m_Group.IsPlayerParty
jne skip // If the player hasn't cast the spell, let it do it's normal thing
cmp [r15+2C],#2 // If m_TargetType is Any
//jne skip // I forgot to put this line in because I'm an idiot
mov r14,#0 // If the party has cast something, and it targets Any, make it target Enemies
skip:
pop rbx //Restore temp register
popfq // Restore flags
cmp r14d,03 //ORIGINAL CODE, checks if switch statement is out of bounds
jmp return
Wouldn't your script just doing "if the players are enemies of the caster, don't select them"? Which isn't anything to do with friendly fire. Friendly fire would be if players are allies of the caster, don't select them. And there's also no differentiating here between positive and negative abilities (i.e. heal and damage), so if you make a change for one it will make a chance for the other too.
How to use this cheat table?
- Install Cheat Engine
- Double-click the .CT file in order to open it.
- Click the PC icon in Cheat Engine in order to select the game process.
- Keep the list.
- Activate the trainer options by checking boxes or setting values from 0 to 1