Author Topic: [DONE] [Suggestion] 'Realistic' Shotgun Behavior  (Read 13690 times)

Offline ohartenstein23

  • Commander
  • *****
  • Posts: 1933
  • Flamethrowers fry cyberdisk circuits
    • View Profile
[DONE] [Suggestion] 'Realistic' Shotgun Behavior
« on: August 13, 2016, 06:46:51 pm »
'Realistic' Shotgun Behavior Executable
Link for Google Drive Archive with Test Mod
Link for Test Mod Only
Link for OXCE+ Executables
Link for GitHub OXCE+ Repository

Based on the discussion in https://openxcom.org/forum/index.php/topic,4744.0.html, I've created an edited version of Yankes' OpenXcom Extended executable to better model realistic shotgun behavior, or at least make the spread pattern of shotgun pellets configurable enough to look realistic.  I've attached a link to a zip archive of the edited source code (in the subfolder OXCE/src) and a mod that demonstrates this new behavior on a few different shotguns.  There's a compiled executable for Ubuntu 14.04 and Windows.  Here's the rundown of what this modification does:

The base behavior of shotgun pellets starts by calculating a normal trajectory like any other weapon for the 'first' pellet projectile.  The following pellets, up to the number defined by shotgunPellets on the ammunition in the ruleset, take the previous trajectory and modify it by the accuracy of the shot minus 5% for each pellet after the first, leading to a wide cone around wherever you clicked.

The new behavior starts the same way by calculating the first trajectory by the normal weapon/firing accuracy, but then each subsequent pellet is spread around the point of impact, with the spread defined by a few new definitions in the ruleset, affected by the range dropoff of the weapon:
  • shotgunSpread:  Defined on an ammunition type as a number between 0 and 100 with a default value of 100.  With shotgunBehavior: true, (100 - shotgunSpread) is approximatley the percent of pellets after the first that will hit the same tile/target as the first at the maximum accurate range; 100 means maximum spread, 0 means most pellets will hit the same target.

    With shotgunBehavior: false, it is a multiplicative modifier to the 5% rule for the previous behavior, such that 100 means full normal spread, 0 means spread only from the weapon's accuracy.
  • shotgunBehavior:  Defined on an ammunition type as 1 or 0, default 0, determines whether or not the new spread calculation will be used (= 1).
  • shotgunChoke:  Defined on a weapon type as a number between 0 and 100 (or higher) with a default value of 100.  Used only for shotgunBehavior: true, acts as a percent modifier to the 'accuracy' of the pellets from shotgunSpread - 100 means only the shotgunSpread value defines the spread pattern, 0 gives maximum possible spread regardless of the shotgunSpread value.

All the ruleset defaults are set such that these changes will not affect weapon/ammunition definitions in current mods, ensuring compatibility and no unexpected changes.

The attached mod borrows a few shotguns from Dioxine's XPiratez mod (https://openxcom.org/forum/index.php/topic,3626.0.html), and adds possible values of the parameters above to give a feeling of what's possible using these changes.

Edit 170130 This has been included in OXCE+ long ago, so the above links to my repositories and .exe's are deprecated in favor of the current OXCE+ version.
« Last Edit: September 28, 2024, 09:29:25 pm by ohartenstein23 »

Offline ohartenstein23

  • Commander
  • *****
  • Posts: 1933
  • Flamethrowers fry cyberdisk circuits
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #1 on: August 13, 2016, 06:50:00 pm »
Here are the changes that I made to the source code: (now out of date, will modify later)

In src/Battlescape/ProjectileFlyBState.cpp, changed these lines under ProjectileFlyBState::think() from
Code: [Select]
https:// special shotgun behaviour: trace extra projectile paths, and add bullet hits at their termination points.
if (shotgun)
{
int i = 1;
while (i != _ammo->getRules()->getShotgunPellets())
{
https:// create a projectile
Projectile *proj = new Projectile(_parent->getMod(), _parent->getSave(), _action, _origin, _targetVoxel, _ammo);
https:// let it trace to the point where it hits
_projectileImpact = proj->calculateTrajectory(std::max(0.0, (_unit->getFiringAccuracy(_action.type, _action.weapon, _parent->getMod()) / 100.0) - i * 5.0));
to
Code: [Select]
https:// special shotgun behaviour: trace extra projectile paths, and add bullet hits at their termination points.
if (shotgun)
{
int spread = _ammo->getRules()->getShotgunSpread();
int choke = _action.weapon->getRules()->getShotgunChoke();
Position firstPelletImpact = _targetVoxel;

int i = 1;
while (i != _ammo->getRules()->getShotgunPellets())
{
https:// create a projectile
Projectile *proj = new Projectile(_parent->getMod(), _parent->getSave(), _action, _origin, _targetVoxel, _ammo);

https:// which type of shotgun behavior to use?
bool groupingBehavior = _ammo->getRules()->getShotgunBehavior();
if (!groupingBehavior)
{
https:// let it trace to the point where it hits
_projectileImpact = proj->calculateTrajectory(std::max(0.0, (_unit->getFiringAccuracy(_action.type, _action.weapon, _parent->getMod()) / 100.0) - i * 5.0 * spread / 100.0));
}
https:// pellet spread based on where first pellet hit
else
{
_targetVoxel = firstPelletImpact;
_projectileImpact = proj->calculateTrajectory(std::max(0.0, (1.0 - spread / 100.0) * choke / 100.0));
}

To expose the calculates to the ruleset, in src/Mod/RuleItem.cpp, the line
Code: [Select]
_maxRange(200), _aimRange(200), _snapRange(15), _autoRange(7), _minRange(0), _dropoff(2), _bulletSpeed(0), _explosionSpeed(0), _autoShots(3), _shotgunPellets(0),
was changed to
Code: [Select]
_maxRange(200), _aimRange(200), _snapRange(15), _autoRange(7), _minRange(0), _dropoff(2), _bulletSpeed(0), _explosionSpeed(0), _autoShots(3), _shotgunPellets(0), _shotgunSpread(100), _shotgunBehavior(false), _shotgunChoke(100),
and the following lines were added to RuleItem::load()
Code: [Select]
_shotgunSpread = node["shotgunSpread"].as<int>(_shotgunSpread);
_shotgunBehavior = node["shotgunBehavior"].as<bool>(_shotgunBehavior);
_shotgunChoke = node["shotgunChoke"].as<int>(_shotgunChoke);
with the functions
Code: [Select]
/**
 * Gets the spread of projectiles from this ammo for use in shotgun behavior.
 * @return The spread.
 */
int RuleItem::getShotgunSpread() const
{
return _shotgunSpread;
}

/**
 * Do the shotgun pellets follow a grouping, or just fired in a cone-like behavior?
 * @return false => cone-like spread, true => grouping
 */
bool RuleItem::getShotgunBehavior() const
{
return _shotgunBehavior;
}

/**
 * Gets the shotgun choke value for modifying pellet spread
 * @return weapon shotgun choke value
 */
int RuleItem::getShotgunChoke() const
{
return _shotgunChoke;
}

Finally, the variables were added to RuleItem.h
Code: [Select]
int _listOrder, _maxRange, _aimRange, _snapRange, _autoRange, _minRange, _dropoff, _bulletSpeed, _explosionSpeed, _autoShots, _shotgunPellets, _shotgunSpread;
bool _shotgunBehavior;
int  _shotgunChoke;

and

https:/// Get the spread of projectiles with shotgun behavior.
int getShotgunSpread() const;
https:/// Get which shotgun spread behavior to use.
bool getShotgunBehavior() const;
https:/// Get the shotgun choke value of this weapon.
int getShotgunChoke() const;

« Last Edit: August 16, 2016, 02:38:33 pm by ohartenstein23 »

Offline Meridian

  • Global Moderator
  • Commander
  • *****
  • Posts: 9055
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #2 on: August 13, 2016, 07:40:54 pm »
Source code?

Offline ohartenstein23

  • Commander
  • *****
  • Posts: 1933
  • Flamethrowers fry cyberdisk circuits
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #3 on: August 15, 2016, 06:40:06 am »
It's in the OXCE folder of the zip archive, and I'm planning on posting the changes here in the thread later today.

Once I figure out how to use it, I can put it on GitHub too.

--- posts merged - Solarius Scorch ---

I'm having trouble with my windows partition - could somebody compile the source and send me a copy of the .exe?
« Last Edit: August 15, 2016, 11:59:03 am by Solarius Scorch »

Offline Meridian

  • Global Moderator
  • Commander
  • *****
  • Posts: 9055
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #4 on: August 15, 2016, 08:30:40 pm »
Took me an hour to make a diff... really should use git :)
Anyway, git patch is attached, if anyone wants to have a look.

A quick question:
1. what is the purpose of this code:

Code: [Select]
https:// pellet spread based on where first pellet hit
_targetVoxel = firstPelletImpact;


I tried it without this code and the _targetVoxel value is not changing anyway... am I missing something?

Use for example this to log the values:

Code: [Select]
Log(LOG_INFO) << "_targetVoxel [x,y,z]: [" << _targetVoxel.x << "," << _targetVoxel.y << "," << _targetVoxel.z << "]";

My output on blunderbuss was:

Code: [Select]
[15-08-2016 19:27:14] [INFO] _targetVoxel [x,y,z]: [344,264,24]
[15-08-2016 19:27:14] [INFO] _targetVoxel [x,y,z]: [344,264,24]
[15-08-2016 19:27:14] [INFO] _targetVoxel [x,y,z]: [344,264,24]
[15-08-2016 19:27:14] [INFO] _targetVoxel [x,y,z]: [344,264,24]
[15-08-2016 19:27:14] [INFO] _targetVoxel [x,y,z]: [344,264,24]

And one more question:
2. why did you change also the vanilla behaviour (by adding spread to it)?

Online Yankes

  • Commander
  • *****
  • Posts: 3326
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #5 on: August 15, 2016, 09:15:02 pm »
Took me an hour to make a diff... really should use git :)
Anyway, git patch is attached, if anyone wants to have a look.

A quick question:
1. what is the purpose of this code:

Code: [Select]
https:// pellet spread based on where first pellet hit
_targetVoxel = firstPelletImpact;

I tried it without this code and the _targetVoxel value is not changing anyway... am I missing something?
I miss this it too. `_targetVoxel` looks that is change only on initing this state, after that it stay constant.



And one more question:
2. why did you change also the vanilla behaviour (by adding spread to it)?
Default is 100 and this probably should give result similar to original.

Offline ohartenstein23

  • Commander
  • *****
  • Posts: 1933
  • Flamethrowers fry cyberdisk circuits
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #6 on: August 15, 2016, 09:48:29 pm »
@Meridian:  I started a fork of your code on github and made a pull request to your branch there, here's the link to my repository: https://github.com/ohartenstein23/OpenXcom/tree/oxce3.0-plus-proto

I must have misread calculateTrajectory in Projectile.cpp - I thought the call to applyAccuracy changed _targetVoxel, and so each call to it would would replace the original value.  The point was that I wanted to make sure the final pellet spread was centered around where the first one hit, rather than always where you clicked.  If it doesn't change at all between calls to calculateTrajectory, then this was unnecessary.  I also didn't know quite how to write to the log; I don't have a whole lot of C++ experience.

And Yankes was right about the change to the vanilla behavior, I wanted to make the vanilla behavior configurable as well, while the default value of shotgunSpread: 100 is to return to the original behavior.

Offline Meridian

  • Global Moderator
  • Commander
  • *****
  • Posts: 9055
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #7 on: August 15, 2016, 10:07:30 pm »
OK, thanks a lot.
I will check it on Wednesday... format a bit, remove unnecessary code, probably change the behaviourType from bool to int... and do some testing.

After that I will merge it to OXCE+ and let Dioxine do the proper testing  8)

Offline ohartenstein23

  • Commander
  • *****
  • Posts: 1933
  • Flamethrowers fry cyberdisk circuits
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #8 on: August 15, 2016, 10:14:45 pm »
Sweet, thanks for taking a look at it.  I originally had shotgunBehavior as an int, I had changed it to bool for readability - I can change it back.  The _targetVoxel thing makes me want to take a second look at this, I'm not sure it's working the way I intended.  I'll commit the changes to the GitHub repository.

Offline Meridian

  • Global Moderator
  • Commander
  • *****
  • Posts: 9055
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #9 on: August 15, 2016, 10:21:02 pm »
The _targetVoxel thing makes me want to take a second look at this, I'm not sure it's working the way I intended.

Yes, please have a look.
The more eyes, the better!

Offline ohartenstein23

  • Commander
  • *****
  • Posts: 1933
  • Flamethrowers fry cyberdisk circuits
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #10 on: August 15, 2016, 10:26:34 pm »
After some testing with output to the log, it looks like the spread isn't actually going around the first pellet impact point, so it always spreads around the tile that was clicked.  Do you know offhand how to get the (x, y, z) position of the impact point, rather than just the target voxel?

Online Yankes

  • Commander
  • *****
  • Posts: 3326
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #11 on: August 15, 2016, 10:53:57 pm »
After some testing with output to the log, it looks like the spread isn't actually going around the first pellet impact point, so it always spreads around the tile that was clicked.  Do you know offhand how to get the (x, y, z) position of the impact point, rather than just the target voxel?
Code: [Select]
_parent->getMap()->getProjectile()->getPosition(offset)

Offline ohartenstein23

  • Commander
  • *****
  • Posts: 1933
  • Flamethrowers fry cyberdisk circuits
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #12 on: August 15, 2016, 11:16:07 pm »
Thanks Yankes, I just found that in the code for where the hit explosion is drawn.

Offline ohartenstein23

  • Commander
  • *****
  • Posts: 1933
  • Flamethrowers fry cyberdisk circuits
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #13 on: August 16, 2016, 12:25:49 am »
Is there a way to cause a calculateTrajectory() call to do the calculation as if CTRL was being held for force fire?  I'm getting a problem where in some instances the extra pellets fail to fire with _projectileImpact = -1 (no line of fire).

Edit: Never mind, I think I found the problem - instead of using getPosition(offset), I used getPosition(-2) to make sure that the position calculated for the impact was not inside an object and therefore the line of fire to the new target isn't obstructed.

Edit:  Repository and archive updated with new code that should be working as intended.  Anyone out there want to compile a Windows executable?
« Last Edit: August 16, 2016, 02:43:30 pm by ohartenstein23 »

Online Yankes

  • Commander
  • *****
  • Posts: 3326
    • View Profile
Re: 'Realistic' Shotgun Behavior Executable
« Reply #14 on: August 16, 2016, 06:48:05 pm »
Is there a way to cause a calculateTrajectory() call to do the calculation as if CTRL was being held for force fire?  I'm getting a problem where in some instances the extra pellets fail to fire with _projectileImpact = -1 (no line of fire).

Edit: Never mind, I think I found the problem - instead of using getPosition(offset), I used getPosition(-2) to make sure that the position calculated for the impact was not inside an object and therefore the line of fire to the new target isn't obstructed.

Edit:  Repository and archive updated with new code that should be working as intended.  Anyone out there want to compile a Windows executable?
As you use Linux you can easy compile it yourself using mxe build chain with this makefile: https://github.com/Yankes/OpenXcom/blob/OpenXcomExtended/src/Makefile.mxe