Jump to content

Photo

Explosives Random Radius


  • Please log in to reply
8 replies to this topic

#1
anUser

anUser

    Fan

  • Members
  • PipPipPip
  • 261 posts

After struggling against OR's, skip tokens and other nasty creatures from the world of hexes, I finally got explosive weapons with an extra random radius. The result may not be very appealing visually, but it indeed works. And this, combined with explosives random damage modlet now defenitively makes grenades something much less certain

Function: XComGame >> XGWeapon >> GetDamageRadius

Original code:

Spoiler

 

Weapon types 7 and 19 are rocket launcher and blaster launcher, respectively. HasUpgrade(25) is Danger Zone perk, and 192 is 3 tiles wide.

 

What I've done is removing the Danger zone check, and add random extra radius to either grenades and rockets

 

New Code:

Spoiler

 

New code in hex:

Spoiler

 

Code break down:

Spoiler

 

ight now once this change applied, when selecting a grenade or a rocket to throw, you'll see the blue semi-sphere marking the area of effect changing it's size constantly, as if blinking, so you can get an idea of how small or how big it can get, but there's no way to tell beforehand how it will end, no matter the size of the blue area at the moment of throwing the grenade, when it explodes it will calculate it again. Therefor I'm expecting inconsistant behaviour from AI, since they won't be able to tell 100% if a grenade will hit their target or won't, so maybe they'll hold some grenade they could throw or maybe they'll miss the grenade because of different random results. Anyway it should be of minor effect, but I'll report if I see it affecting in a relevant manner.

 

an please someone tell me how those skip token work? I assume they operate like: if previous condition evaluates to true, then skip the rest of checks (useful for conditions with a bunch of OR's, when it's either one or another or another one, so when one evals true just skip that section) but the numbers following the 18 puzzle me. I assume it's also some offset in little endian or however it's called, but the number itself I don't know what it should be. I got it working just by trial and error, but I can't see what it represents... and it's not even multiple of 4. Any clue?

 

edit: typo, copy-pasting, etc


Edited by anUser, 25 March 2013 - 02:58 AM.


#2
Amineri

Amineri

    Resident poster

  • Premium Member
  • 3,927 posts

Very nice -- more randomness. In games like this, randomness typically hurts the player more then the AI. From a statistical point of view, the expected average result is that the player will win. The greater the randomness (i.e. the variance), the greater the likelihood that the AI will have the advantage. Plus, probabilistic decision trees are much much harder to navigate -- this is why there aren't any good Backgammon-playing computer programs like there are for chess.

 

As to the boolean operator optimization tokens: I looked at those a little while ago. The number after the token appears to be a relative offset to jump. Jump statements use absolute offsets (absolute with respect to the start of the function, anyhow). The boolean token offsets are relative to the token position -- it jumps ahead that many bytes if the optimization triggers (bytes are virtual bytes, not file-size bytes).

 

The optimization triggers are :

OR -- first boolean is true, expression is true

AND -- first boolean false, expression is false



#3
anUser

anUser

    Fan

  • Members
  • PipPipPip
  • 261 posts

Yeah, as I suspected. Then I'm not counting well. I was taking the values from UE expl in view tokens, besides each item there's a number which I thought it was virtual size... but there are things I ignore if they should be counted like native functions that only take 1 byte. In this example...

(0x000) JumpIfNot(34) -> NativeFunction(31) -> NativeFunction(13) -> InstanceVariable(9) -> IntConstByte(2) -> EndFunctionParms(1) -> Skip(16) -> NativeFunction(13) -> InstanceVariable(9) -> IntConstByte(2) -> EndFunctionParms(1) -> EndFunctionParms(1)
    if((m_eType == 85) || m_eType == 88)

I know the offset is 14 (0E) because I've been trying, but I cannot figure this offset from this.

... and if I were to change several skips, as I pretend, if there's only OR's (A || B || C || D), the first "skip" points to "outside" the condition, so every successive skip token "skips less", right?

 

if I get it all in one sentence I'll try to bring back danger zone perk, as I've realized now this affects suppression area. btw I've been playing for a while with this and grenade random damage and I must say it's absolutely great. I'm playing a new game, got only 4 soldiers and faced a bunch of sectoids... what a difference now, when before throwing a grenade meant killing 3+ sectoids (including psi-link deaths) now it's completely different, you never know if that grenade will even be a kill. I've also reduced damage to 3 to increase the dramatizing effect, and sure it does.

 

A side note, I'm thinking if this were used on other weapons, given they had radius > 0 (I've tested changing it in the ini, it works), this random radius thing could be used to cause accidental friendly fire, or taking it further, make shotguns behave like shotguns, getting increased radius and decreased damage per distance.... if that were possible



#4
Amineri

Amineri

    Resident poster

  • Premium Member
  • 3,927 posts

You should be able to save space by not using the optimization tokens. They are only optimizers, not required items. Without them, the second statement of an OR operation will be evaluated even if the first statement was true.

 

Since there aren't exactly a huge number of boolean operations being checked here, it should be fine time-wise to leave them out. That might free up some more bytes to fit in more functionality.

 

However, I have run into troubles trying to rewrite some boolean operations (when trying to get the weapon itemcard to show for SHIV weapons -- which still doesn't work). So, you might take this advice with a grain of salt.



#5
anUser

anUser

    Fan

  • Members
  • PipPipPip
  • 261 posts

that's strange... I tried to write the condition without the skip token and with just two elements to evaluate and I couldn't get it to work until I put in the skip token... maybe I wasn't writting it properly or it was an error of endparam tokens (too much, too few) sometimes they seem to compile well but then they throw execution time errors... I'll give it another go, but I'd really appreciate if someone can point out how to count virtual bytes just in case I have to use the skip tokens, and just for knowing. I'll try to sum up what I've discovered so far, please let me know if I'm wrong or there's something I'm missing.

 

local variables take 5 physical bytes, starting with 01 (as in this example), and I've seen and used this technique of invoking a local variable just to take up virtual space so ifs and jumps keep pointing where they should and in order to preserve original virtual size, and I've noticed each invocation it takes 4 bytes. Knowing this and the original virtual size and current position of edn-of-script token I could calculate how many variable calls I have to make.

I've noticed there are things that don't make VS increase, like all of those 1 byte items, like operators, native functions, etc, is it because they take also 1 byte of "virtual size", whatever it means?

 

So, when counting towards this skip tokens, should I count 9 for local variables and 1 for native functions? Do 16 endParam tokens count as well? Anything I should exclude from counting?

 

I've managed to work with jumps/gotos, if/else, cause ue explorer tells where does each line start, so absolute offset is ok so far

 

btw, the original function made use of lots of explicit casting, even in the conditions where checked m_eType == 7 both values were converted to integer. I've tried without converting them and it works as well. I'm wondering if this is a common procedure in programming for the sake of security and consistency, or it's just code leftovers or compilation-time stuff that have nothing to do with how the original code was written...?



#6
anUser

anUser

    Fan

  • Members
  • PipPipPip
  • 261 posts

I've finally got it written in one line, with added "Danger Zone" perk check. I had to use skip tokens after each "OR", fortunately I got it quickly enough.

 

Now the code reads:

simulated function float GetDamageRadius()
{
    // End:0xE2
    if((m_eType == 85) || (m_eType == 88) || (m_eType == 7) || (m_eType == 19) || m_kOwner.GetCharacter().HasUpgrade(25))
    {
        return float(m_kTWeapon.iRadius + Rand(m_kTWeapon.iRadius));                                                                                                                                                                                                                                                                        
    }
    return float(m_kTWeapon.iRadius);
    //return ReturnValue;    
}

 

I got the values for the skip tokens' offset from UE Explorer, in view tokens mode:

(0x000) JumpIfNot(130) -> NativeFunction(127) -> NativeFunction(13) -> InstanceVariable(9) -> IntConstByte(2) -> EndFunctionParms(1) -> Skip(112) -> NativeFunction(109) -> NativeFunction(13) -> InstanceVariable(9) -> IntConstByte(2) -> EndFunctionParms(1) -> Skip(94) -> NativeFunction(91) -> NativeFunction(13) -> InstanceVariable(9) -> IntConstByte(2) -> EndFunctionParms(1) -> Skip(76) -> NativeFunction(73) -> NativeFunction(13) -> InstanceVariable(9) -> IntConstByte(2) -> EndFunctionParms(1) -> Skip(58) -> Context(55) -> Context(31) -> InstanceVariable(9) -> VirtualFunction(10) -> EndFunctionParms(1) -> VirtualFunction(12) -> IntConstByte(2) -> EndFunctionParms(1) -> EndFunctionParms(1) -> EndFunctionParms(1) -> EndFunctionParms(1) -> EndFunctionParms(1)
    if((m_eType == 85) || (m_eType == 88) || (m_eType == 7) || (m_eType == 19) || m_kOwner.GetCharacter().HasUpgrade(25))

Notice the values right after Skip(112) -> NativeFunction(109), that PLUS ONE is the value for the skip tokens.

 

Now the code in hex is:

Spoiler

 

 

Now the radius may grow randomly up to double it's original radius, so I recommend setting them lower in DGC.ini. I'm currently playing with this values:

Frag grenade: 128 (from 2 to 4 tiles wide) Damage: 3

Alien grenade: 160 (from 2.5 to 5 tiles wide) Damage: 4

Rocket launcher: 192 (from 3 to 6 tiles wide) Damage: 5

Blaster launcher: 256 (from 4 to 8 tiles wide) Damage: 7

+ random +/-1 damage

 

As it is now the same check validates either for explosives OR for Danger Zone perk, because having both would have been ridiculous (I love the ability on MG but on missiles it kinda feels lame) so now machineguns (or every weapon with a radius greater than zero set in the ini, and in the hands of a soldier with the danger zone ability) will benefit from this randomly increased radius, not only on suppression, but also on regular shots.

I'm currently testing a radius of 64, which is 1 tile wide, so in theory it could end up covering 2 tiles wide, but I suspect it might affect more units at once depending on how the maths are done exactly. I'll try to find out, or most probably I'll just play it and adjust it as I see fit :P

 

Well if anyone decides to give it a try let me know what you think about it, if there's some interesting idea there's still some room left to add some small improvement.

 

Oh, and if someone figures out whether it's possible to create local variables, and how if so, I'd be very thankful. I could definitively compress that code pretty much and add a bunch of variations with a switch only that I could create a variable here. I guess I can use some other unused class variable.. and hope it isn't really used nor it gets removed next patch.



#7
Amineri

Amineri

    Resident poster

  • Premium Member
  • 3,927 posts

Excellent job on getting this working!  :dance:

 

Toning down the deterministic (and powerful) effects of grenades is a good thing, I think. Randomized damage + randomized radius = a lot more uncertainty. The only thing left is to have the toss location end up randomized (i.e. not perfect aim).

 

The game will probably need some rebalancing, though, as grenades were one of the principle ways to get advantage in the early game, which could already be tough on Impossible.

 

One question I had was regarding the actual radius. From earlier observations I'd noticed that it isn't a true 3D explosive sphere -- it doesn't seem to affect units above the aim point. Did you see anything in there relating to that, or is it buried deeper in?

 

I guess your experience shows why my boolean checks didn't work (crashed at run-time). That's good to know ... now I can go back and try to get the weapon item cards to work for the SHIV weapons. Thanks a bunch for the info!



#8
anUser

anUser

    Fan

  • Members
  • PipPipPip
  • 261 posts

Not only it's less deterministic about output damage (whether you'll damage or kill your targets) but it also makes it you can no longer control 100% environment damage. How many times you've tossed a grenade just in the right position to kill an alien but not to damage that car one of your units is using as a cover? Try it now and you'll now risk.

 

The game will probably need some rebalancing, though, as grenades were one of the principle ways to get advantage in the early game, which could already be tough on Impossible.

I've choosen to boost MG and sniper by giving rifles and pistols long range penalty, including aliens', so you get the advantadge against sectoids and such at mid/long range combat, but close combat is always dangerous. I'm currently using explosives more as a mean to blow up covers rather than killing enemies, though.

 

 One question I had was regarding the actual radius. From earlier observations I'd noticed that it isn't a true 3D explosive sphere -- it doesn't seem to affect units above the aim point. Did you see anything in there relating to that, or is it buried deeper in?

I haven't noticed that. At least for environment damage it seems to work as a sphere, I even recall seeing some wall being broken by the half down, and many times I've thrown a grenade above a car to hit the aliens around, and both aliens and the car got damaged all the times... but I'll keep an eye of it, although now it gets harder to confirm. Btw I haven't seen neither I've looked for the code responsible for the actual maths, I just happened to find that function.



#9
Amineri

Amineri

    Resident poster

  • Premium Member
  • 3,927 posts

From what I've read (and partially experienced), the explosive damage only appears to affect the level of the explosion and the level below.

 

I have experienced exploding a rocket BELOW a aliens (in one of the construction yard missions where the aliens can start on floors 2 or 3) and the alien was unaffected.

 

However, it would not surprise me in the least if this were buried somewhere deep down in the Unreal Engine code.






IPB skins by Skinbox
Page loaded in: 1.090 seconds