-
-
Notifications
You must be signed in to change notification settings - Fork 0
Dual Wield: API Changes
I recommend to disable Two Handed Weapons
when using offhand weapon to have a better experience.
If you want to keep the option on, you might want to bind the speed key to another button (default to offhand grip)
Under the controls menu you find a new command named Update missing defaults
, just below the reset command, this will update the missing bindings to default state, use it to update the new missing default bindings!
offhand trigger
- Offhand fire
main grip + offhand trigger
- Offhand alternate fire
main grip + joy up / down
- Switch between offhand weapons
main grip + main joystick left
- Bring the main weapon to the off hand
main grip + main joystick right
- Bring the offhand weapon to the main hand
offhand grip
- The new default speed key, previously set to offhand trigger
💡 Brutal Doom and similar mods, dual wield will work with quirks. State jump depending on inventory items will not work well with dual wield.
💡 Sharing the same overlay layer on multiple weapons will not work with dual wield.
💡 When using A_PlaySound or A_StartSound, 0 and 1 are the most safe channels to use, when using other channels you need to be aware that a second weapon held in the off hand might start a sound on that same channel at the same time.
bool OverrideAttackPosDir
vector3 AttackPos
double AttackAngle
double AttackPitch
double AttackRoll
vector3 AttackDir(Actor actor, double angle, double pitch)
Usage
Return the current direction of the main weapon in relation to the orientation of the given actor, angle and pitch are not offset, they are the addition of the actual angle of the actor + offset if exists.
Parameters
- actor - this is the player actor
- angle - yaw angle of the player + offset angle (you want the offset if you are calculating the speed vector but NOT for the spawn position)
- pitch - pitch angle of the player + offset angle (you want the offset if you are calculating the speed vector but NOT for the spawn position)
You can find an example that might help you understand the use of this function in the implementation of P_RailAttack, there is also an example at the end of this document
vector3 OffhandPos
double OffhandAngle
double OffhandPitch
double OffhandRoll
vector3 OffhandDir(Actor actor, double angle, double pitch)
Usage
Return the current direction of the offhand weapon in relation to the orientation of the given actor, angle and pitch are not offset, they are the addition of the actual angle of the actor + offset if exists.
Parameters
- actor - this is the player actor
- angle - yaw angle of the player + offset angle (you want the offset if you are calculating the speed vector but NOT for the spawn position)
- pitch - pitch angle of the player + offset angle (you want the offset if you are calculating the speed vector but NOT for the spawn position)
You can find an example that might help you understand the use of this function in the implementation of P_RailAttack, there is also an example at the end of this document
ACS Definition | Corresponding action |
---|---|
BT_OFFHANDATTACK | Fire primary with offhand weapon |
BT_OFFHANDALTATTACK | Fire secondary with offhand weapon |
BT_OFFHANDRELOAD | Reload with offhand weapon |
BT_MAINHANDRELOAD | Reload with mainhand weapon |
WEAPON.OFFHANDWEAPON
- The weapon will be placed on the offhand
WEAPON.NOHANDSWITCH
- The weapon can not be moved from one hand to the other
WEAPON.TWOHANDED
- The weapon is a two hand weapon so it can not be used together with other weapons, switching to this weapon remove the other weapon currently wield.
WEAPON.NOAUTOREVERSE
- The model will not be reversed when moving the weapon to the offhand.
The following flags can be used to tell to shoot from the offhand instead of mainhand when using the following functions:
LAF_ISOFFHAND
TRF_ISOFFHAND
- The weapon should be considered as offhand weapon
TRF_USEWEAPON
- The line originates from the calling actor's weapon (default to ReadyWeapon)
ALF_ISOFFHAND
ALF_ISOFFHAND
RAF_ISOFFHAND
Actor SpawnSubMissile(Class type, Actor target, int aimflags = 0, double angle = 1e37)
New parameters:
-
aimflags: the following flags are available:
-
ALF_ISOFFHAND
- the weapon should be considered as offhand weapon.
-
- angle: change the angle of the missile velocity vector (default to player angle).
Actor, Actor SpawnPlayerMissile(class type, double angle = 1e37, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0, double pitch = 1e37)
New parameters:
-
aimflags: the following flags are available:
-
ALF_ISOFFHAND
- the weapon should be considered as offhand weapon.
-
- pitch: can be used to change the pitch of the missile, default to player pitch.
Action that make use of weapon position data to calculate spawned object position and velocity vector
action void A_MyCustomAction()
{
let weapon = invoker;
if (weapon && player.mo.OverrideAttackPosDir)
{
Vector3 dir;
Vector3 yoffsetDir;
Vector3 zoffsetDir;
Vector3 spawnpos;
Vector3 newvel;
let directionAngle = angle;
let directionPitch = pitch;
let directionRoll = roll;
if (weapon.bOffhandWeapon)
{
spawnpos = player.mo.OffhandPos;
directionRoll = -player.mo.OffhandRoll;
dir = player.mo.OffhandDir(self, angle, pitch);
yoffsetDir = player.mo.OffhandDir(self, angle - 90, pitch);
zoffsetDir = player.mo.OffhandDir(self, angle, pitch + 90);
}
else
{
spawnpos = player.mo.AttackPos;
directionRoll = -player.mo.AttackRoll;
dir = player.mo.AttackDir(self, angle, pitch);
yoffsetDir = player.mo.AttackDir(self, angle - 90, pitch);
zoffsetDir = player.mo.AttackDir(self, angle, pitch + 90);
}
directionAngle = dir.x;
directionPitch = dir.y;
// offset in relation to the weapon to spawn the new object
double xofs = 10;
double yofs = 0;
double zofs = 0;
// ========== SIMPLE SPAWN POS CALCULATION =============
// simple position calculation based only on xofs and yofs
spawnpos += (xofs * cos(dir.x) + yofs * sin(dir.x), xofs * sin(dir.x) - yofs * cos(dir.x), 0);
// or we can use the method RotateVector
spawnpos += (RotateVector(xofs, yofs, directionAngle), 0);
// =======================
// ========== BETTER SPAWN POS CALCULATION =============
// spawn position contribution with x offset by taking in consideration the orientation of the weapon
spawnpos += (
xofs * cos(dir.x) * cos(dir.y),
xofs * sin(dir.x) * cos(dir.y),
xofs * -sin(dir.y)
);
// spawn position contribution with y offset by taking in consideration the orientation of the weapon
spawnpos += (
yofs * cos(yoffsetDir.x) * cos(yoffsetDir.y),
yofs * sin(yoffsetDir.x) * cos(yoffsetDir.y),
yofs * -sin(yoffsetDir.y)
);
// spawn position contribution with z offset by taking in consideration the orientation of the weapon
spawnpos += (
zofs * cos(zoffsetDir.y) * cos(zoffsetDir.x),
zofs * cos(zoffsetDir.y) * sin(zoffsetDir.x),
zofs * -sin(zoffsetDir.y)
);
// =======================
let mo = Spawn(missile, spawnpos, ALLOW_REPLACE);
if (mo)
{
mo.Angle = directionAngle;
mo.Pitch = directionPitch;
mo.Roll = directionRoll;
// =========== SIMPLE VELOCITY VECTOR (ONLY FORWARD COMPONENT) ============
// if we use the spawned object speed (forward only) then we can just do the following
newvel = (
mo.Speed * cos(dir.y) * cos(dir.x),
mo.Speed * cos(dir.y) * sin(dir.x),
mo.Speed * -sin(dir.y)
);
mo.Vel = newvel;
// depending on your case you might want to use a slope for the z component
double slope = -clamp(tan(directionPitch), -5, 5);
mo.Vel.Z = mo.Speed * slope;
// =======================
// =========== BETTER VELOCITY VECTOR (X,Y,Z COMPONENT) ============
// if the velocity vector has x, y and z components we need to add all three contributions
newvel = (0, 0, 0);
newvel += (
x * cos(dir.x) * cos(dir.y),
x * sin(dir.x) * cos(dir.y),
x * -sin(dir.y)
);
newvel += (
y * cos(yoffsetDir.x) * cos(yoffsetDir.y),
y * sin(yoffsetDir.x) * cos(yoffsetDir.y),
y * -sin(yoffsetDir.y)
);
newvel += (
z * cos(zoffsetDir.y) * cos(zoffsetDir.x),
z * cos(zoffsetDir.y) * sin(zoffsetDir.x),
z * -sin(zoffsetDir.y)
);
mo.Vel = newvel;
// =======================
}
}
}