I'm currently trying to make a replacement for A_FireBullets and A_FireProjectile that doesn't deal with any gimbal-locking business.
While the method posted below does work for player hitscans (though I might've forgotten to add the flash function?), projectile aiming is extremely wonky when I test it out.
I don't know if it's because I'm applying the calculations wrong when it comes to projectiles, or if I'm not using A_FireProjectile right, or if it's something else entirely.
I'll see if I can figure out a way to get the function to work in the meantime, but help on this would be mundo-appreciated.
Also, on a lesser note, is there a better, more efficient way to go about the implementations below?
Relevant Code Blocks
A quaternion called playerAngle exists outside the two functions to save on copy/pasting.
Code: Select all
//pDir: Player Direction, amplitude: Random Devation Mode
static vector3, vector3 GimbalUnlocker(quat pDir, vector2 direction, vector2 offset, bool amplitude = false)
{
quat offy;
vector3 up = (0, 0, 1), forwards = (1, 0, 0), left = (0, 1, 0), finalDir, finalOff, offTemp;
if(amplitude)
{
double temppyX = frandom(-direction.x, direction.x);
double temppyY = frandom(-direction.y, direction.y);
offy = (Quat.AxisAngle(up, temppyX)) * (Quat.AxisAngle(left, temppyY));
}
else
{
offy = (Quat.AxisAngle(up, direction.x)) * (Quat.AxisAngle(left, direction.y));
}
offTemp = pDir * (offset.x, offset.y, 0);
finalOff = level.Vec3Offset((0, 0, 0), offTemp);
finalDir = pDir * offy * forwards;
return finalDir, finalOff;
}
Code: Select all
action void WeponBoolet(int num, uint dam, uint modu,
vector2 deviation, bool nomAmmo = true,
uint ammoNom = 1, bool explicit = false,
bool flashy = true, bool soundy = true,
vector2 offsets = (0, 0))
{
if(nomAmmo && !invoker.DepleteAmmo(invoker.bAltFire, true, ammoNom)) {return;}
if(flashy) {PlayerPawn(self).PlayAttacking2();}
if(soundy) {A_StartSound(player.ReadyWeapon.AttackSound, CHAN_WEAPON);}
uint iterations = abs(num); if(num == 0) {iterations = 1;}
double autoPitch = BulletSlope(), ying, yang;
invoker.playerAngle = Quat.FromAngles(angle, autoPitch, roll);
vector3 dirry, ofsetty;
bool firstOne = (num == 1) && (!player.refire);
for(uint i = 0; i < iterations; i++)
{
int finalDam = dam * random(1, modu);
ying = 0; yang = 0;
bool applyS = ((i != 0) && !firstOne && (num != 0)) && !explicit;
[dirry, ofsetty] = GimbalUnlocker(invoker.playerAngle, deviation, offsets, applyS);
ying = atan2(dirry.y, dirry.x); yang = -asin(dirry.z);
LineAttack(ying, PLAYERMISSILERANGE, yang, finalDam, 'Hitscan',
"BulletPuff", 0, null, ofsetty.z, ofsetty.x, ofsetty.y);
}
}
Code: Select all
action void WeponProj(class<Actor> flingy, vector2 eulerAng = (0, 0), vector2 offsets = (0, 0),
bool nomAmmo = true, EFireCustomMissileFlags customFlags = FPF_NOAUTOAIM)
{
vector3 dirry, ofsetty;
invoker.playerAngle = Quat.FromAngles(angle, pitch, roll);
[dirry, ofsetty] = GimbalUnlocker(invoker.playerAngle, eulerAng, offsets, false);
double ying = atan2(dirry.y, dirry.x), yang = -asin(dirry.z);
A_FireProjectile(flingy, ying, nomAmmo, ofsetty.y, ofsetty.z, customFlags, yang);
}