Implement M47 Dragon (#6773)

* abc

* Revert "abc"

This reverts commit bcb4214bd9.

* Update to current commit

* Ports over NouberNou's dragon guidance

* Add Dragon model

* Make the Dragon CSW capable

* Fix bugs regarding argument order

* Add Dragon Attack Profile. Change how missileGuidance guidance_pfh works in order to allow for different types of missiles besides continious thrust

* Fix bug regarding missile direction. Add official US Army training manual for the dragon for reference purposes

* Adjust model to reflect real-life one

* Add attackProfile and guidanceProfile onFired functions

* Change Dragon "onFired" to reflect missileGuidance changes

* Only implementing the Super-Dragon. Remove Tabs. Add new lines to all files. Add string-table. Tweak missile flight dynamics

* Add sight description

* Fix inheritance issues. Missile damage values tweaked. Fix String Table. Add backblast area.

* Add feature wiki page.

* Fix picture issues

* Remove Dragon manual

* add missing semi-colon

* Tweak damage values. Fix formatting. Add lazy evaluation where applicable

* Disable the ability to switch to the unusable launcher. Convert rvmat numbers to equivalent but more readable numbers. Multiple code fixes. ace_csw required. Formatting fixes. TGA -> PAA. Remove unused comments in missile guidance code

* Dragon flight dynamics tweaked. Now assuming there is a booster angle creating wobble. Add a slight delay when the wire breaks to fire all of the service charges

* hpp newline fixes. Case sensitivity for model and rvmat references

* Update Wiki dependencies

* Revert "Update Wiki dependencies"

This reverts commit efc298c481.

* fix dependency component

* Changed inheritance structure to be more rigid. Remove un-needed config values. Fix script issues regarding positioning and the launchers aliveness

* get rid of the optic for the base dragon. fucking bi configs not making sense

* Lock non-useable dragon on initialization

* Add model.cfg for animations

* Fix formatting. Fix M47 Dragon Optic zoom

* Change LOD selection names

* Revert indentation, keep parenthesis. "Start, stop, start stop! Jesus! I'm starting to think Mattis is just a big cock tease"

* Re-update indentation of model.cfg

* Path fix. Whitespace fix

* Sight attach/detach on same vehicle

* If the sight gets detached, make sure the dragon goes dumb. Remove resetting of resting position when gunner gets out - looks stupid, but when the dragon is fired weird stuff happens

* disable debug

* Add EOF

* Maybe finally fix EOF problem
This commit is contained in:
Brandon Danyluk 2019-06-07 22:48:37 -06:00 committed by PabstMirror
parent b1d5bbe450
commit abe2ce2f6f
67 changed files with 1387 additions and 46 deletions

View File

@ -0,0 +1 @@
z\ace\addons\dragon

View File

@ -0,0 +1,11 @@
class EGVAR(missileguidance,AttackProfiles) {
class DRAGON {
name = CSTRING(dragonName);
visualName = CSTRING(dragonName);
description = CSTRING(dragonName);
onFired = QFUNC(onFired);
functionName = QFUNC(attackProfile_DRAGON);
};
};

147
addons/dragon/CfgAmmo.hpp Normal file
View File

@ -0,0 +1,147 @@
class CfgAmmo {
class ammo_Penetrator_Base;
class M_Scalpel_AT;
class Rocket_03_AP_F;
class GVAR(penetrator_super): ammo_Penetrator_Base {
caliber = 60;
warheadName = "HEAT";
hit = 460;
fuseDistance = 75;
};
class GVAR(dragonBase): Rocket_03_AP_F {
EGVAR(frag,skip) = 1;
scope = 1;
aiAmmoUsageFlags = "128+512";
model = QPATHTOF(models\dragon.p3d);
maxSpeed = 200;
thrust = 300;
initTime = 0.151;
thrustTime = 0;
sideAirFriction = 0.05;
effectsMissile = "missile2";
effectFlare = "";
airFriction = 0.5;
fuseDistance = 75;
whistleDist = 2;
hit = 100;
indirectHit = 9;
indirectHitRange = 1;
explosive = 0.8;
timeToLive = 60;
cost = 500;
simulationStep = 0.005;
maxControlRange = 1500;
class ace_missileguidance {
minDeflection = 0;
maxDeflection = 0;
incDeflection = 0;
canVanillaLock = 0;
// Guidance type for munitions
defaultSeekerType = "SACLOS";
seekerTypes[] = { "SACLOS" };
defaultSeekerLockMode = "LOAL";
seekerLockModes[] = { "LOAL", "LOBL" };
seekLastTargetPos = 0;
seekerAngle = 30;
seekerAccuracy = 1;
seekerMinRange = 65;
seekerMaxRange = 1000;
correctionDistance = 30;
missileLeadDistance = 0;
offsetFromCrosshair[] = { 0, 0, 0 };
serviceInterval = 0.33; // how many seconds between pops
serviceCharges = 32; // how many charges are in this missile
serviceChargeAcceleration = 6.5;
dragonSpeed = 100; // meters per second
defaultAttackProfile = "DRAGON";
attackProfiles[] = {"DRAGON"};
};
};
class GVAR(super) : GVAR(dragonBase) {
submunitionAmmo = QGVAR(penetrator_super);
submunitionDirectionType = "SubmunitionModelDirection";
submunitionInitSpeed = 1000;
submunitionParentSpeedCoef = 0;
submunitionInitialOffset[] = { 0, 0, -0.2 };
class ace_missileguidance {
enabled = 1;
// Guidance type for munitions
defaultSeekerType = "SACLOS";
seekerTypes[] = { "SACLOS" };
defaultSeekerLockMode = "LOAL";
seekerLockModes[] = { "LOAL", "LOBL" };
seekLastTargetPos = 0;
seekerAngle = 30;
seekerAccuracy = 1;
seekerMinRange = 30;
seekerMaxRange = 1500;
correctionDistance = 30;
missileLeadDistance = 0;
serviceInterval = 0.33; // how many seconds between pops
serviceCharges = 60; // how many charges are in this missile
serviceChargeAcceleration = 6.5;
dragonSpeed = 100; // meters per second
defaultAttackProfile = "DRAGON";
attackProfiles[] = {"DRAGON"};
};
};
class ShellBase;
class GVAR(serviceCharge) : ShellBase {
hit = 1;
indirectHit = 2;
indirectHitRange = 1;
typicalSpeed = 100;
explosive = 1;
cost = 300;
model = "\A3\Weapons_F\empty.p3d";
airFriction = 0;
timeToLive = 1;
explosionTime = 0.001;
soundFly[] = {"",1,1};
soundEngine[] = {"",1,4};
CraterEffects = "";
explosionEffects = QGVAR(serviceExplosion);
hitarmor[] = {"soundDefault1", 1};
hitbuilding[] = {"soundDefault1", 1};
hitconcrete[] = {"soundDefault1", 1};
hitdefault[] = {"soundDefault1", 1};
hitfoliage[] = {"soundDefault1", 1};
hitglass[] = {"soundDefault1", 1};
hitglassarmored[] = {"soundDefault1", 1};
hitgroundhard[] = {"soundDefault1", 1};
hitgroundsoft[] = {"soundDefault1", 1};
hitiron[] = {"soundDefault1", 1};
hitman[] = {"soundDefault1", 1};
hitmetal[] = {"soundDefault1", 1};
hitmetalplate[] = {"soundDefault1", 1};
hitplastic[] = {"soundDefault1", 1};
hitrubber[] = {"soundDefault1", 1};
hitwood[] = {"soundDefault1", 1};
sounddefault1[] = {QPATHTOF(sounds\service_charge.wss), 56.2341, 1, 1800};
soundHit[] = {QPATHTOF(sounds\service_charge.wss),56.23413,1,1800};
multiSoundHit[] = {"soundDefault1", 1};
};
};

View File

@ -0,0 +1,17 @@
class Extended_PreStart_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preStart));
};
};
class Extended_PreInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preInit));
};
};
class Extended_PostInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_postInit));
};
};

View File

@ -0,0 +1,16 @@
class CfgMagazines {
class 1Rnd_GAA_missiles;
class GVAR(super) : 1Rnd_GAA_missiles {
sound[] = {};
soundFly[] = {};
soundHit[] = {};
model = QPATHTOF(models\dragon.p3d);
ammo = QGVAR(super);
initSpeed = 120;
scope = 1;
displayName = CSTRING(dragonName);
displayNameShort = CSTRING(dragonName);
descriptionShort = CSTRING(dragonDescription);
};
};

View File

@ -0,0 +1,149 @@
class CfgVehicles {
class LandVehicle;
class StaticWeapon: LandVehicle {
class Turrets;
class MainTurret;
class ACE_Actions {
class ACE_MainActions {};
};
};
class StaticATWeapon: StaticWeapon {};
class GVAR(staticBase): StaticATWeapon {
scope = 1;
author = ECSTRING(common,ACETeam);
displayname = CSTRING(dragonName);
side = 1;
faction = "BLU_F";
crew = "B_soldier_f";
model = QPATHTOF(models\ace_m47_static.p3d);
picture = "\A3\Static_F_Gamma\data\UI\gear_StaticTurret_AT_CA.paa";
UiPicture = "\A3\Static_F_Gamma\data\UI\gear_StaticTurret_AT_CA.paa";
icon = "\A3\Static_F_Gamma\data\UI\map_StaticTurret_AT_CA.paa";
threat[] = {0.7,1.0,0.1};
cost = 150000;
class Damage {
tex[] = {};
mat[] = {
"a3\static_f_gamma\data\staticturret_01.rvmat",
"a3\static_f_gamma\data\staticturret_01_damage.rvmat",
"a3\static_f_gamma\data\staticturret_01_destruct.rvmat",
"a3\static_f_gamma\data\staticturret_02.rvmat",
"a3\static_f_gamma\data\staticturret_02_damage.rvmat",
"a3\static_f_gamma\data\staticturret_02_destruct.rvmat",
"a3\weapons_f_beta\launchers\titan\data\titan_launcher.rvmat",
"a3\weapons_f_beta\launchers\titan\data\titan_launcher_damage.rvmat",
"a3\weapons_f_beta\launchers\titan\data\titan_launcher_destruct.rvmat",
"a3\weapons_f_beta\launchers\titan\data\titan_mtube.rvmat",
"a3\weapons_f_beta\launchers\titan\data\titan_mtube_damage.rvmat",
"a3\weapons_f_beta\launchers\titan\data\titan_mtube_destruct.rvmat"
};
};
class Turrets: Turrets {
class MainTurret: MainTurret {
optics = 1;
turretInfoType = "RscWeaponEmpty";
gunnerOpticsModel = QPATHTOF(models\optics_m47.p3d);
minElev = -30;
maxElev = 20;
weapons[] = { QGVAR(dummyStatic) };
magazines[] = { QGVAR(super) };
gunnerAction = "gunner_static_low01";
gunnergetInAction = "";
gunnergetOutAction = "";
discreteDistance[] = {};
discreteDistanceInitIndex = 0;
displayName = CSTRING(dragonName);
class ViewOptics {
initAngleX = 0;
minAngleX = -30;
maxAngleX = 30;
initAngleY = 5;
minAngleY = -100;
maxAngleY = 100;
initFov = 0.055;
minFov = 0.055; // 6 degree FOV
maxFov = 0.055;
visionMode[] = {"Normal"};
thermalMode[] = {0};
};
gunnerRightHandAnimName = "OtocHlaven_shake";
gunnerLeftHandAnimName = "OtocHlaven_shake";
gunBeg = "spice rakety";
gunEnd = "konec rakety";
memoryPointGunnerOptics = "look";
};
};
class AnimationSources {
class rest_rotate {
source="user";
animPeriod=0.00001;
initPhase=-0.35;
maxValue="3.60";
minValue="-3.60";
};
class optic_hide {
source="user";
animPeriod=0.0001;
initPhase=1;
maxValue="1";
minValue="0";
};
class missile_hide {
source="user";
animPeriod=0.0001;
initPhase=0;
maxValue="1";
minValue="0";
};
};
soundGetOut[] = {"A3\sounds_f\dummysound",0.001,1,5};
soundGetIn[] = {"A3\sounds_f\dummysound",0.00031622776,1,5};
armorStructural = 10.0;
class ACE_CSW {
disassembleTo = QGVAR(super);
};
class ACE_Actions: ACE_Actions {
class ACE_MainActions: ACE_MainActions {
displayName = CSTRING(dragonName);
class GVAR(pickUp) {
displayName = ECSTRING(csw,Pickup_displayName);
condition = QUOTE(call FUNC(canPickupTripod));
statement = QUOTE(call EFUNC(csw,assemble_pickupTripod));
};
class GVAR(attachSight) {
displayName = CSTRING(attachSight);
condition = QUOTE(call FUNC(sightCanAttach));
statement = QUOTE(call FUNC(sightAttach));
};
class GVAR(detachSight) {
displayName = CSTRING(detachSight);
condition = QUOTE(call FUNC(sightCanDetach));
statement = QUOTE(call FUNC(sightDetach));
};
};
};
};
class GVAR(staticAssembled): GVAR(staticBase) {
scope = 2;
class AnimationSources: AnimationSources {
class optic_hide: optic_hide {
initPhase = 0;
};
};
class Turrets: Turrets {
class MainTurret: MainTurret {
weapons[] = { QGVAR(superStatic) };
};
};
};
};

View File

@ -0,0 +1,90 @@
class CfgWeapons {
class launch_Titan_base;
class Launcher_Base_F;
class missiles_titan;
class Binocular;
class Default;
class missiles_titan_static: missiles_titan {
class WeaponSlotsInfo;
};
class launch_Titan_F: launch_Titan_base {
class WeaponSlotsInfo;
};
class GVAR(super): launch_Titan_F {
model = QPATHTOF(models\ace_m47_magazine.p3d);
picture = QPATHTOF(data\m47_dragon_item_ca.paa);
magazines[] = {};
displayName = CSTRING(dragonName);
descriptionShort = CSTRING(dragonDescription);
scope = 2;
class ACE_CSW {
type = "mount";
deployTime = 2;
pickupTime = 2;
deploy = QGVAR(staticBase);
};
class WeaponSlotsInfo: WeaponSlotsInfo {
mass = 253;
};
modes[] = {};
};
class GVAR(superStatic): missiles_titan_static {
EGVAR(overpressure,angle) = 90;
EGVAR(overpressure,range) = 30;
EGVAR(overpressure,damage) = 0.85;
initSpeed = 120;
displayName = CSTRING(dragonName);
descriptionShort = CSTRING(dragonDescription);
magazines[] = { QGVAR(super) };
};
// need a weapon in order to rotate turret
class GVAR(dummyStatic): Default {
cursor = "";
cursorAim = "";
scope = 1;
displayName = CSTRING(dragonName);
reloadTime = 0;
canLock = 0;
optics = 0;
enableAttack = 0;
};
class GVAR(sight): Binocular {
displayName = CSTRING(sightName);
model = QPATHTOF(models\ace_m47_optic.p3d);
picture = QPATHTOF(data\m47_daysight_item_ca.paa);
optics = 1;
weaponInfoType = "RscWeaponEmpty";
modelOptics = QPATHTOF(models\optics_m47);
reloadaction = "";
showSwitchAction = 1;
useAsBinocular = 1;
uipicture = "";
descriptionShort = CSTRING(sightDescription);
ace_disposable = 0;
magazines[] = {};
type = 4096;
opticsPPEffects[] = {"OpticsCHAbera1","OpticsBlur1"};
opticsZoomMin = 0.055;
opticsZoomMax = 0.055;
scope = 2;
class ACE_CSW {
type = "weapon";
deployTime = 2;
pickupTime = 1;
class assembleTo {
GVAR(super_noSight) = QGVAR(super_sight);
};
};
class WeaponSlotsInfo {
mass = 68;
};
};
};

12
addons/dragon/README.md Normal file
View File

@ -0,0 +1,12 @@
ace_dragon
===================
Adds M47 Dragon Missile.
## Maintainers
The people responsible for merging changes to this component or answering potential questions.
- [Brandon-TCVM](https://github.com/TheCandianVendingMachine)

View File

@ -0,0 +1,7 @@
PREP(attackProfile_DRAGON);
PREP(canPickupTripod);
PREP(onFired);
PREP(sightAttach);
PREP(sightCanAttach);
PREP(sightCanDetach);
PREP(sightDetach);

View File

@ -0,0 +1,37 @@
#include "script_component.hpp"
[QGVAR(detachSight), LINKFUNC(sightDetach)] call CBA_fnc_addEventHandler;
[QGVAR(attachSight), LINKFUNC(sightAttach)] call CBA_fnc_addEventHandler;
["vehicle", {
params ["","_vehicle"];
TRACE_2("vehicle change",_vehicle,typeOf _vehicle);
if (!(_vehicle isKindOf QGVAR(staticBase))) exitWith {};
_vehicle animate ["rest_rotate", 0];
if (isNil QGVAR(pfID)) then {GVAR(pfID) = -1};
[GVAR(pfID)] call CBA_fnc_removePerFrameHandler;
private _lastView = cameraView;
if (!(_lastView in ["INTERNAL", "EXTERNAL"])) then { _lastView == "INTERNAL"; };
GVAR(pfID) = [{
params ["_args"];
(_this select 0) params ["_vehicle", "_lastView"];
if ((!alive _vehicle) || {!alive ACE_player} || {(vehicle ACE_player) != _vehicle}) exitWith {
TRACE_1("exiting PFEH",GVAR(pfID));
[GVAR(pfID)] call CBA_fnc_removePerFrameHandler;
};
if (cameraView in ["INTERNAL", "EXTERNAL"]) then {
_args set [1, cameraView];
} else {
if ((cameraOn == _vehicle) && {!(_vehicle getVariable [QGVAR(sightAttached), ((typeOf _vehicle) == QGVAR(staticAssembled))])}) then {
_vehicle switchCamera _lastView;
};
};
}, 0, [_vehicle, _lastView]] call CBA_fnc_addPerFrameHandler;
TRACE_1("started PFEH",GVAR(pfID));
}, true] call CBA_fnc_addPlayerEventHandler;

View File

@ -0,0 +1,10 @@
#include "script_component.hpp"
ADDON = false;
PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;
ADDON = true;

View File

@ -0,0 +1,4 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

BIN
addons/dragon/anim/M47.rtm Normal file

Binary file not shown.

View File

@ -0,0 +1,119 @@
class cfgSkeletons {
class OFP2_ManSkeleton {
isDiscrete = 0;
skeletonInherit = "";
skeletonBones[] = {
"Pelvis","",
"Spine","Pelvis",
"Spine1","Spine",
"Spine2","Spine1",
"Spine3","Spine2",
"camera","Pelvis",// case has changed for arma3
"weapon","Spine1",
"launcher","Spine1",
"Neck","Spine3",
"Neck1","Neck",
"Head","Neck1", //Head skeleton in hierarchy
//Left upper side
"LeftShoulder","Spine3",
"LeftArm","LeftShoulder",
"LeftArmRoll","LeftArm",
"LeftForeArm","LeftArmRoll",
"LeftForeArmRoll","LeftForeArm",
"LeftHand","LeftForeArmRoll",
"LeftHandRing","LeftHand",
"LeftHandRing1","LeftHandRing",
"LeftHandRing2","LeftHandRing1",
"LeftHandRing3","LeftHandRing2",
"LeftHandPinky1","LeftHandRing",
"LeftHandPinky2","LeftHandPinky1",
"LeftHandPinky3","LeftHandPinky2",
"LeftHandMiddle1","LeftHand",
"LeftHandMiddle2","LeftHandMiddle1",
"LeftHandMiddle3","LeftHandMiddle2",
"LeftHandIndex1","LeftHand",
"LeftHandIndex2","LeftHandIndex1",
"LeftHandIndex3","LeftHandIndex2",
"LeftHandThumb1","LeftHand",
"LeftHandThumb2","LeftHandThumb1",
"LeftHandThumb3","LeftHandThumb2",
//Right upper side
"RightShoulder","Spine3",
"RightArm","RightShoulder",
"RightArmRoll","RightArm",
"RightForeArm","RightArmRoll",
"RightForeArmRoll","RightForeArm",
"RightHand","RightForeArmRoll",
"RightHandRing","RightHand",
"RightHandRing1","RightHandRing",
"RightHandRing2","RightHandRing1",
"RightHandRing3","RightHandRing2",
"RightHandPinky1","RightHandRing",
"RightHandPinky2","RightHandPinky1",
"RightHandPinky3","RightHandPinky2",
"RightHandMiddle1","RightHand",
"RightHandMiddle2","RightHandMiddle1",
"RightHandMiddle3","RightHandMiddle2",
"RightHandIndex1","RightHand",
"RightHandIndex2","RightHandIndex1",
"RightHandIndex3","RightHandIndex2",
"RightHandThumb1","RightHand",
"RightHandThumb2","RightHandThumb1",
"RightHandThumb3","RightHandThumb2",
//Left lower side
"LeftUpLeg","Pelvis",
"LeftUpLegRoll","LeftUpLeg",
"LeftLeg","LeftUpLegRoll",
"LeftLegRoll","LeftLeg",
"LeftFoot","LeftLegRoll",
"LeftToeBase","LeftFoot",
//Right lower side
"RightUpLeg","Pelvis",
"RightUpLegRoll","RightUpLeg",
"RightLeg","RightUpLegRoll",
"RightLegRoll","RightLeg",
"RightFoot","RightLegRoll",
"RightToeBase","RightFoot",
//New facial features arma3 only
"Face_Hub","Head",
"Face_Jawbone","Face_Hub",
"Face_Jowl","Face_Jawbone",
"Face_chopRight","Face_Jawbone",
"Face_chopLeft","Face_Jawbone",
"Face_LipLowerMiddle","Face_Jawbone",
"Face_LipLowerLeft","Face_Jawbone",
"Face_LipLowerRight","Face_Jawbone",
"Face_Chin","Face_Jawbone",
"Face_Tongue","Face_Jawbone",
"Face_CornerRight","Face_Hub",
"Face_CheekSideRight","Face_CornerRight",
"Face_CornerLeft","Face_Hub",
"Face_CheekSideLeft","Face_CornerLeft",
"Face_CheekFrontRight","Face_Hub",
"Face_CheekFrontLeft","Face_Hub",
"Face_CheekUpperRight","Face_Hub",
"Face_CheekUpperLeft","Face_Hub",
"Face_LipUpperMiddle","Face_Hub",
"Face_LipUpperRight","Face_Hub",
"Face_LipUpperLeft","Face_Hub",
"Face_NostrilRight","Face_Hub",
"Face_NostrilLeft","Face_Hub",
"Face_Forehead","Face_Hub",
"Face_BrowFrontRight","Face_Forehead",
"Face_BrowFrontLeft","Face_Forehead",
"Face_BrowMiddle","Face_Forehead",
"Face_BrowSideRight","Face_Forehead",
"Face_BrowSideLeft","Face_Forehead",
"Face_Eyelids","Face_Hub",
"Face_EyelidUpperRight","Face_Hub",
"Face_EyelidUpperLeft","Face_Hub",
"Face_EyelidLowerRight","Face_Hub",
"Face_EyelidLowerLeft","Face_Hub",
"EyeLeft","Face_Hub",
"EyeRight","Face_Hub"
};// end of skeleton array
// location of pivot points (local axes) for hierarchical animation
pivotsModel="A3\anims_f\data\skeleton\SkeletonPivots.p3d";
};
};

42
addons/dragon/config.cpp Normal file
View File

@ -0,0 +1,42 @@
#include "script_component.hpp"
class CfgPatches {
class ADDON {
name = COMPONENT_NAME;
units[] = {};
weapons[] = {};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ace_common","ace_missileguidance","ace_hot","ace_csw"};
author = ECSTRING(common,ACETeam);
authors[] = {"Brandon (TCVM)"};
url = ECSTRING(main,URL);
VERSION_CONFIG;
};
};
#include "ACE_GuidanceConfig.hpp"
#include "CfgEventHandlers.hpp"
#include "CfgWeapons.hpp"
#include "CfgMagazines.hpp"
#include "CfgAmmo.hpp"
#include "CfgVehicles.hpp"
class GVAR(serviceExplosion) {
class Light1 {
simulation = "light";
type = "GrenadeExploLight";
position[] = {0,0,0};
intensity = 0.005;
interval = 1;
lifeTime = 0.5;
};
class GrenadeSmoke1 {
simulation = "particles";
type = "ImpactSmoke2";
position[] = {0,0,0};
intensity = 0.15;
interval = 0.1;
lifeTime = 0.5;
};
};

View File

@ -0,0 +1,81 @@
class StageTI {
texture="z\ace\addons\dragon\data\m47_ti_ca.paa";
};
ambient[]={0.958,0.984,1,1};
diffuse[]={0.958,0.984,1,1};
forcedDiffuse[]={0,0,0,0};
emmisive[]={0,0,0,1};
specular[]={0.153,0.169,0.111,1};
specularPower=90;
PixelShaderID="Super";
VertexShaderID="Super";
class Stage1 {
texture="z\ace\addons\dragon\data\m47_nohq.paa";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};
class Stage2 {
texture="a3\weapons_f\Data\DetailMaps\Metal_rough_DT.paa";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};
class Stage3 {
texture="#(argb,8,8,3)color(0,0,0,0,MC)";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};
class Stage4 {
texture="z\ace\addons\dragon\data\m47_as.paa";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};
class Stage5 {
texture="z\ace\addons\dragon\data\m47_smdi.paa";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};
class Stage6 {
texture="#(ai,32,128,1)fresnel(4.01,2.86)";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};
class Stage7 {
texture="a3\data_f\env_land_co.paa";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};

View File

@ -0,0 +1,81 @@
class StageTI {
texture="z\ace\addons\dragon\data\m47_ti_ca.paa";
};
ambient[]={0.989,1,0.958,1};
diffuse[]={0.989,1,0.958,1};
forcedDiffuse[]={0,0,0,0};
emmisive[]={0,0,0,1};
specular[]={0.159,0.212,0.196,1};
specularPower=90;
PixelShaderID="Super";
VertexShaderID="Super";
class Stage1 {
texture="z\ace\addons\dragon\data\m47mis_nohq.paa";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};
class Stage2 {
texture="a3\weapons_f\Data\DetailMaps\Metal_rough_DT.paa";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};
class Stage3 {
texture="#(argb,8,8,3)color(0,0,0,0,MC)";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};
class Stage4 {
texture="#(argb,8,8,3)color(1,1,1,1,AS)";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};
class Stage5 {
texture="z\ace\addons\dragon\data\m47mis_smdi.paa";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};
class Stage6 {
texture="#(ai,32,128,1)fresnel(4.01,2.86)";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};
class Stage7 {
texture="a3\data_f\env_land_co.paa";
uvSource="tex";
class uvTransform {
aside[]={1,0,0};
up[]={0,1,0};
dir[]={0,0,1};
pos[]={0,0,0};
};
};

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,77 @@
#include "script_component.hpp"
/*
* Author: Brandon (TCVM) (Code inspired by NouberNou's Dragon Guidance)
* Attack profile: Dragon Guidance
*
* Arguments:
* 0: Seeker Target PosASL <ARRAY>
* 1: Guidance Arg Array <ARRAY>
* 2: Attack Profile State <ARRAY>
*
* Return Value:
* Missile Aim PosASL <ARRAY> - Unused
*
* Example:
* [[1,2,3], [], []] call ace_dragon_fnc_attackProfile_DRAGON;
*
* Public: No
*/
params ["_seekerTargetPos", "_args", "_attackProfileStateParams"];
_args params ["_firedEH", "", "", "", "_stateParams"];
_firedEH params ["_shooter","_weapon","","","","","_projectile"];
_attackProfileStateParams params ["_maxCorrectableDistance", "_wireCut", "_seekerMaxRangeSqr", "_seekerMinRangeSqr", "_wireCutSource", "_lastTime", "_serviceInterval", "_serviceChargeCount", "_serviceChargeAcceleration", "_dragonSpeed"];
private _projectilePos = getPosASL _projectile;
private _distanceToProjectile = (getPosASL _shooter) vectorDistanceSqr _projectilePos;
private _retPos = _projectilePos vectorAdd (AGLtoASL (_projectile vectorModelToWorld [0, 50, 0]));
// _shooter returns the vehicle that shot it. If the launcher dies, the wire would probably be cut so assume it
if ((_distanceToProjectile > _seekerMaxRangeSqr) || _wireCut || { !alive _shooter }) exitWith {
// wire snap, random direction
if (!_wireCut) then {
_attackProfileStateParams set [1, true];
playSound3D ["a3\sounds_f\air\sfx\SL_rope_break.wss", objNull, false, AGLtoASL (_shooter modelToWorld _wireCutSource), 150, 1, 25];
};
if (_serviceChargeCount > 0 && {(_lastTime - CBA_missionTime) <= 0}) then {
_attackProfileStateParams set [5, CBA_missionTime + 0.05 + random 0.1];
private _randomVector = [(random 2) - 1, random 1, (random 2) - 1];
_projectile setVelocityModelSpace ((velocityModelSpace _projectile) vectorAdd (_randomVector vectorMultiply _serviceChargeAcceleration));
private _charge = createVehicle [QGVAR(serviceCharge), [0, 0, 0], [], 0, "NONE"];
_charge setPosASL (_projectilePos vectorAdd ((_randomVector vectorMultiply -1) vectorMultiply 0.025));
_attackProfileStateParams set [7, _serviceChargeCount - 1];
};
_retPos
};
if (_distanceToProjectile <= _seekerMinRangeSqr || { _serviceChargeCount <= 0 } || { !(_shooter getVariable [QGVAR(sightAttached), true]) }) exitWith { _retPos };
// if the time between updates is less than the pop time we want to fire the rockets OR if the missile wants to make a major correction pop it rapidly
if (((_lastTime - CBA_missionTime) <= 0) || {(_lastTime - CBA_missionTime) < (_serviceInterval / 2) && (_projectilePos vectorDistance _seekerTargetPos > 1)}) then {
_attackProfileStateParams set [5, CBA_missionTime + _serviceInterval];
private _vectorToCrosshair = vectorNormalized (_projectile worldToModel (ASLToAGL _seekerTargetPos));
private _vectorToPos = vectorNormalized (((_projectile vectorWorldToModelVisual (_shooter weaponDirection _weapon)) vectorMultiply (_dragonSpeed * _serviceInterval)) vectorAdd (_vectorToCrosshair vectorMultiply _maxCorrectableDistance));
if ((_vectorToPos select 2) < 0) then {
_vectorToPos set [2, 0];
} else {
private _a = _vectorToPos select 1;
private _b = _vectorToPos select 2;
// The booster has some angle to it, so we introduce that axis if the angle is too low
if (abs(_a) > 0 && { abs(atan (_b / _a)) < DRAGON_BOOSTER_ANGLE }) then {
_vectorToPos set [2, abs(_a)];
};
};
_projectile setVelocityModelSpace ((velocityModelSpace _projectile) vectorAdd (_vectorToPos vectorMultiply _serviceChargeAcceleration));
private _charge = createVehicle [QGVAR(serviceCharge), [0, 0, 0], [], 0, "NONE"];
_charge setPosASL (_projectilePos vectorAdd ((_vectorToCrosshair vectorMultiply -1) vectorMultiply 0.025));
_attackProfileStateParams set [7, _serviceChargeCount - 1];
};
_retPos

View File

@ -0,0 +1,25 @@
#include "script_component.hpp"
/*
* Author: Brandon (TCVM)
* Determines if you can pick-up the Dragon missile. If the missile was fired you will not be able to pick up the tripod.
*
* Arguments:
* 0: Target <OBJECT>
* 1: Unit Performing Action <OBJECT>
*
* Return Value:
* Can Pickup Tripod <BOOL>
*
* Example:
* [vehicle player, player] call ace_dragon_fnc_canPickupTripod;
*
* Public: No
*/
params ["_target", "_unit"];
(alive _target)
&& {!alive (gunner _target)}
&& {!(_target getVariable [QGVAR(fired), false])}
&& {!(_target getVariable [QGVAR(sightAttached), ((typeOf _target) == QGVAR(staticAssembled))])}
&& EFUNC(csw,assemble_canPickupTripod)

View File

@ -0,0 +1,53 @@
#include "script_component.hpp"
/*
* Author: Brandon (TCVM)
* Runs when Dragon is fired
*
* Arguments:
* 0: None
* 1: The weapon that was fired <OBJECT>
*
* Return Value:
* None
*
* Example:
* [any, vehicle player] call ace_dragon_fnc_onFired;
*
* Public: No
*/
params ["_firedEH", "", "", "_seekerParams", "_stateParams"];
_firedEH params ["_shooter","_weapon","","","","","_projectile"];
_stateParams params ["", "", "_attackProfileStateParams"];
_seekerParams params ["", "", "_seekerMaxRange", "_seekerMinRange"];
_shooter setVariable [QGVAR(fired), true, true];
_shooter animate ["missile_hide", 1];
private _config = ([_projectile] call CBA_fnc_getObjectConfig) >> "ace_missileguidance";
private _serviceInterval = [_config >> "serviceInterval", "NUMBER", 0.33] call CBA_fnc_getConfigEntry;
private _serviceChargeCount = [_config >> "serviceCharges", "NUMBER", 60] call CBA_fnc_getConfigEntry;
private _serviceChargeAcceleration = [_config >> "serviceChargeAcceleration", "NUMBER", 6.5] call CBA_fnc_getConfigEntry;
private _dragonSpeed = [_config >> "dragonSpeed", "NUMBER", 100] call CBA_fnc_getConfigEntry;
private _maxCorrectableDistance = [_config >> "correctionDistance", "NUMBER", DEFAULT_CORRECTION_DISTANCE] call CBA_fnc_getConfigEntry;
private _maxDistanceSqr = _seekerMaxRange * _seekerMaxRange;
private _minDistanceSqr = _seekerMinRange * _seekerMinRange;
private _turretPath = [_shooter, _weapon] call CBA_fnc_turretPathWeapon;
private _turretConfig = [_shooter, _turretPath] call CBA_fnc_getTurret;
private _wireCutSource = _shooter selectionPosition getText(_turretConfig >> "missileEnd");
_attackProfileStateParams append [
_maxCorrectableDistance,
false,
_maxDistanceSqr,
_minDistanceSqr,
_wireCutSource,
CBA_missionTime,
_serviceInterval,
_serviceChargeCount,
_serviceChargeAcceleration,
_dragonSpeed
];

View File

@ -0,0 +1,32 @@
#include "script_component.hpp"
/*
* Author: Brandon (TCVM)
* Attaches the sighting unit to the Dragon missile.
*
* Arguments:
* 0: Target <OBJECT>
* 1: Unit Performing Action <OBJECT>
*
* Return Value:
* Can Attach Sighting Unit <BOOL>
*
* Example:
* [cursorObject, player] call ace_dragon_fnc_sightAttach
*
* Public: No
*/
params ["_target", "_unit", ["_event", false]];
TRACE_3("sightAttach",_target,_unit,_event);
if (_event isEqualTo true) then {
if (!(_target turretLocal [0])) exitWith {};
_target setVariable [QGVAR(sightAttached), true, true];
_target animate ["optic_hide", 0];
_target addWeapon QGVAR(superStatic);
_target removeWeapon QGVAR(dummyStatic);
TRACE_2("added sight",_target weaponsTurret [0],_target animationPhase "optic_hide");
} else {
_unit removeWeapon QGVAR(sight);
[QGVAR(attachSight), [_target, _unit, true]] call CBA_fnc_globalEvent;
};

View File

@ -0,0 +1,24 @@
#include "script_component.hpp"
/*
* Author: Brandon (TCVM)
* Determines if you can attach the sighting unit to the Dragon missile.
*
* Arguments:
* 0: Target <OBJECT>
* 1: Unit Performing Action <OBJECT>
*
* Return Value:
* Can Attach Sighting Unit <BOOL>
*
* Example:
* [cursorObject, player] call ace_dragon_fnc_sightCanAttach
*
* Public: No
*/
params ["_target", "_unit"];
(alive _target)
// && {!(_target getVariable [QGVAR(fired), false])}
&& {!(_target getVariable [QGVAR(sightAttached), ((typeOf _target) == QGVAR(staticAssembled))])}
&& {QGVAR(sight) in (weapons _unit)}

View File

@ -0,0 +1,23 @@
#include "script_component.hpp"
/*
* Author: Brandon (TCVM)
* Determines if you can attach the sighting unit to the Dragon missile.
*
* Arguments:
* 0: Target <OBJECT>
* 1: Unit Performing Action <OBJECT>
*
* Return Value:
* Can Attach Sighting Unit <BOOL>
*
* Example:
* [cursorObject, player] call ace_dragon_fnc_sightCanDetach
*
* Public: No
*/
params ["_target", "_unit"];
(alive _target)
// && {!(_target getVariable [QGVAR(fired), false])}
&& {_target getVariable [QGVAR(sightAttached), ((typeOf _target) == QGVAR(staticAssembled))]}

View File

@ -0,0 +1,38 @@
#include "script_component.hpp"
/*
* Author: Brandon (TCVM)
* Attaches the sighting unit to the Dragon missile.
*
* Arguments:
* 0: Target <OBJECT>
* 1: Unit Performing Action <OBJECT>
*
* Return Value:
* Can Attach Sighting Unit <BOOL>
*
* Example:
* [cursorObject, player] call ace_dragon_fnc_sightDetach;
*
* Public: No
*/
params ["_target", "_unit"];
params ["_target", "_unit", ["_event", false]];
TRACE_3("sightDetach",_target,_unit,_event);
if (_event isEqualTo true) then {
if (!(_target turretLocal [0])) exitWith {};
_target setVariable [QGVAR(sightAttached), false, true];
_target animate ["optic_hide", 1];
_target removeWeapon QGVAR(superStatic);
_target addWeapon QGVAR(dummyStatic);
TRACE_2("removed sight",_target weaponsTurret [0],_target animationPhase "optic_hide");
} else {
if ((binocular _unit) == "") then {
_unit addWeapon QGVAR(sight);
} else {
[_unit, QGVAR(sight)] call EFUNC(common,addToInventory);
};
[QGVAR(detachSight), [_target, _unit, true]] call CBA_fnc_globalEvent;
};

View File

@ -0,0 +1 @@
#include "\z\ace\addons\dragon\script_component.hpp"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,94 @@
class CfgSkeletons {
class Default {
isDiscrete = 1;
skeletonInherit = "";
skeletonBones[] = {};
};
class ace_m47_static_skeleton: Default {
skeletonInherit = "Default";
skeletonBones[] = {
"bipod","",
"grav_box","bipod",
"launcher","grav_box",
"optic","launcher",
"missile","launcher"
};
};
};
class CfgModels {
class Default {
sectionsInherit = "";
sections[] = {};
};
class ace_m47_static: Default {
sectionsInherit = "Default";
sections[] = {};
skeletonName = "ace_m47_static_skeleton";
class Animations {
class MainGun {
type="rotation";
selection="launcher";
sourceAddress = "clamp";
source="MainGun";
axis="elevate_axis";
animPeriod=0.01;
initPhase=0;
maxValue="rad 360";
minValue="rad -360";
angle1="rad 360";
angle0="rad -360";
};
class MainTurret {
type="rotation";
source="MainTurret";
selection="bipod";
sourceAddress = "loop";
axis="rotate_axis";
animPeriod=0.005;
minValue="rad -360";
maxValue="rad +360";
angle0="rad -360";
angle1="rad +360";
};
class rest_rotate {
type="rotation";
selection="grav_box";
sourceAddress = "clamp";
source="user";
axis="elevate_axis";
animPeriod=0.00001;
initPhase=-0.35;
maxValue="3.60";
minValue="-3.60";
angle1="rad -360";
angle0="rad 360";
};
class optic_hide {
type = "hide";
source = "user";
selection = "optic";
animPeriod = 0.0001;
minValue = 0;
maxValue = 1;
minPhase = 0;
maxPhase = 1;
hideValue = 0.99;
initPhase = 1;
};
class missile_hide {
type = "hide";
source = "user";
selection = "missile";
animPeriod = 0.0001;
minValue = 0;
maxValue = 1;
minPhase = 0;
maxPhase = 1;
hideValue = 0.99;
};
};
};
};

Binary file not shown.

View File

@ -0,0 +1,18 @@
#define COMPONENT dragon
#define COMPONENT_BEAUTIFIED M47 Dragon
#include "\z\ace\addons\main\script_mod.hpp"
// #define DEBUG_MODE_FULL
// #define DISABLE_COMPILE_CACHE
// #define ENABLE_PERFORMANCE_COUNTERS
#ifdef DEBUG_ENABLED_DRAGON
#define DEBUG_MODE_FULL
#endif
#ifdef DEBUG_SETTINGS_DRAGON
#define DEBUG_SETTINGS DEBUG_SETTINGS_DRAGON
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#define DRAGON_BOOSTER_ANGLE 45

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<Project name="ACE">
<Package name="dragon">
<Key ID="STR_ACE_dragon_dragonName">
<English>M47 Super-Dragon</English>
</Key>
<Key ID="STR_ACE_dragon_dragonNoSight">
<English>M47 Super-Dragon (No Sight)</English>
</Key>
<Key ID="STR_ACE_dragon_dragonSight">
<English>M47 Super-Dragon (With Sight)</English>
</Key>
<Key ID="STR_ACE_dragon_attachSight">
<English>Attach Sight</English>
</Key>
<Key ID="STR_ACE_dragon_detachSight">
<English>Detach Sight</English>
</Key>
<Key ID="STR_ACE_dragon_sightName">
<English>SU-36/P Daysight</English>
</Key>
<Key ID="STR_ACE_dragon_sightDescription">
<English>A light, cheap sight used for daytime operations. Contains the guidance computer for the whole system</English>
</Key>
<Key ID="STR_ACE_dragon_dragonDescription">
<English>A Wire-Guided SACLOS missile with a unique flight characteristic</English>
</Key>
</Package>
</Project>

View File

@ -5,6 +5,7 @@ class EGVAR(missileguidance,AttackProfiles) {
description = CSTRING(missileType_Description); description = CSTRING(missileType_Description);
functionName = QFUNC(attackProfile_WIRE); functionName = QFUNC(attackProfile_WIRE);
onFired = QFUNC(wire_onFired);
}; };
}; };
class EGVAR(missileguidance,SeekerTypes) { class EGVAR(missileguidance,SeekerTypes) {
@ -14,6 +15,7 @@ class EGVAR(missileguidance,SeekerTypes) {
description = CSTRING(SACLOS_Description); description = CSTRING(SACLOS_Description);
functionName = QFUNC(seekerType_SACLOS); functionName = QFUNC(seekerType_SACLOS);
onFired = QFUNC(SACLOS_onFired);
}; };
}; };

View File

@ -70,8 +70,6 @@ class CfgAmmo {
defaultSeekerLockMode = "LOAL"; defaultSeekerLockMode = "LOAL";
seekerLockModes[] = { "LOAL", "LOBL" }; seekerLockModes[] = { "LOAL", "LOBL" };
onFired = QFUNC(onFired);
seekLastTargetPos = 0; // seek last target position [if seeker loses LOS of target, continue to last known pos] seekLastTargetPos = 0; // seek last target position [if seeker loses LOS of target, continue to last known pos]
seekerAngle = 30; // Angle from the shooter's view that can track the missile seekerAngle = 30; // Angle from the shooter's view that can track the missile
seekerAccuracy = 1; // seeker accuracy multiplier seekerAccuracy = 1; // seeker accuracy multiplier

View File

@ -1,4 +1,5 @@
PREP(seekerType_SACLOS); PREP(seekerType_SACLOS);
PREP(attackProfile_WIRE); PREP(attackProfile_WIRE);
PREP(onFired); PREP(wire_onFired);
PREP(SACLOS_onFired);

View File

@ -0,0 +1,35 @@
#include "script_component.hpp"
/*
* Author: Brandon (TCVM)
* Sets up SACLOS state arrays (called from missileGuidance's onFired).
*
* Arguments:
* Guidance Arg Array <ARRAY>
*
* Return Value:
* None
*
* Example:
* [] call ace_hot_fnc_SACLOS_onFired
*
* Public: No
*/
params ["_firedEH", "", "", "", "_stateParams"];
_firedEH params ["_shooter","_weapon","","","","","_projectile"];
_stateParams params ["", "_seekerStateParams"];
private _config = ([_projectile] call CBA_fnc_getObjectConfig) >> "ace_missileguidance";
private _distanceAheadOfMissile = [_config >> "missileLeadDistance", "NUMBER", DEFAULT_LEAD_DISTANCE] call CBA_fnc_getConfigEntry;
if (_shooter isKindOf "Plane") then { WARNING("SACLOS fired from planes unsupported"); };
private _turretPath = [_shooter, _weapon] call CBA_fnc_turretPathWeapon;
private _turretConfig = [_shooter, _turretPath] call CBA_fnc_getTurret;
private _memoryPointGunnerOptics = getText(_turretConfig >> "memoryPointGunnerOptics");
private _animationSourceBody = getText(_turretConfig >> "animationSourceBody");
private _animationSourceGun = getText(_turretConfig >> "animationSourceGun");
_seekerStateParams set [0, _memoryPointGunnerOptics];
_seekerStateParams set [1, _animationSourceBody];
_seekerStateParams set [2, _animationSourceGun];
_seekerStateParams set [3, _distanceAheadOfMissile];

View File

@ -19,7 +19,7 @@
params ["_seekerTargetPos", "_args", "_attackProfileStateParams"]; params ["_seekerTargetPos", "_args", "_attackProfileStateParams"];
_args params ["_firedEH"]; _args params ["_firedEH"];
_firedEH params ["_shooter","","","","","","_projectile"]; _firedEH params ["_shooter","","","","","","_projectile"];
_attackProfileStateParams params["_maxCorrectableDistance", "_wireCut", "_randomVector", "_crosshairOffset", "_seekerMaxRangeSqr", "_wireCutSource"]; _attackProfileStateParams params["_maxCorrectableDistance", "_wireCut", "_randomVector", "_crosshairOffset", "_seekerMaxRangeSqr", "", "_wireCutSource"];
private _projectilePos = getPosASL _projectile; private _projectilePos = getPosASL _projectile;

View File

@ -25,7 +25,7 @@ _seekerStateParams params ["_memoryPointGunnerOptics", "_animationSourceBody", "
private _shooterPos = AGLToASL (_shooter modelToWorld(_shooter selectionPosition _memoryPointGunnerOptics)); private _shooterPos = AGLToASL (_shooter modelToWorld(_shooter selectionPosition _memoryPointGunnerOptics));
private _projPos = getPosASL _projectile; private _projPos = getPosASL _projectile;
private _lookDirection = if !(_shooter isKindOf "CAManBase") then { private _lookDirection = if !(_shooter isKindOf "CAManBase" || {_shooter isKindOf "StaticWeapon"}) then {
private _gBody = -deg(_shooter animationPhase _animationSourceBody); private _gBody = -deg(_shooter animationPhase _animationSourceBody);
private _gGun = deg(_shooter animationPhase _animationSourceGun); private _gGun = deg(_shooter animationPhase _animationSourceGun);

View File

@ -1,7 +1,7 @@
#include "script_component.hpp" #include "script_component.hpp"
/* /*
* Author: Brandon (TCVM) * Author: Brandon (TCVM)
* Sets up missile guidance state arrays (called from missileGuidance's onFired). * Sets up wireGuided state arrays (called from missileGuidance's onFired).
* *
* Arguments: * Arguments:
* Guidance Arg Array <ARRAY> * Guidance Arg Array <ARRAY>
@ -10,26 +10,26 @@
* None * None
* *
* Example: * Example:
* [] call ace_hot_fnc_onFired * [] call ace_hot_fnc_wire_onFired
* *
* Public: No * Public: No
*/ */
params ["_firedEH", "", "", "_seekerParams", "_stateParams"]; params ["_firedEH", "", "", "_seekerParams", "_stateParams"];
_firedEH params ["_shooter","_weapon","","","","","_projectile", "_gunner"]; _firedEH params ["_shooter","_weapon","","","","","_projectile", "_gunner"];
_stateParams params ["", "_seekerStateParams", "_attackProfileStateParams"]; _stateParams params ["", "", "_attackProfileStateParams"];
_seekerParams params ["", "", "_seekerMaxRange"]; _seekerParams params ["", "", "_seekerMaxRange", "_seekerMinRange"];
private _config = ([_projectile] call CBA_fnc_getObjectConfig) >> "ace_missileguidance"; private _config = ([_projectile] call CBA_fnc_getObjectConfig) >> "ace_missileguidance";
private _maxCorrectableDistance = [_config >> "correctionDistance", "NUMBER", DEFAULT_CORRECTION_DISTANCE] call CBA_fnc_getConfigEntry; private _maxCorrectableDistance = [_config >> "correctionDistance", "NUMBER", DEFAULT_CORRECTION_DISTANCE] call CBA_fnc_getConfigEntry;
private _crosshairOffset = [_config >> "offsetFromCrosshair", "ARRAY", [0, 0, 0]] call CBA_fnc_getConfigEntry;
private _maxDistanceSqr = _seekerMaxRange * _seekerMaxRange; private _maxDistanceSqr = _seekerMaxRange * _seekerMaxRange;
private _distanceAheadOfMissile = [_config >> "missileLeadDistance", "NUMBER", DEFAULT_LEAD_DISTANCE] call CBA_fnc_getConfigEntry; private _minDistanceSqr = _seekerMinRange * _seekerMinRange;
// AI don't know how to use the crosshair offset becauze they dum dum // AI don't know how to use the crosshair offset becauze they dum dum
if ((_gunner != ACE_PLAYER) && {_gunner != (ACE_controlledUAV select 1)}) then { _crosshairOffset = if ((_gunner != ACE_PLAYER) && {_gunner != (ACE_controlledUAV select 1)}) then {
_crosshairOffset = [0, 0, 0]; [0, 0, 0];
} else {
[_config >> "offsetFromCrosshair", "ARRAY", [0, 0, 0]] call CBA_fnc_getConfigEntry
}; };
if (_shooter isKindOf "Plane") then {WARNING("SACLOS fired from planes unsupported");};
private _turretPath = [_shooter, _weapon] call CBA_fnc_turretPathWeapon; private _turretPath = [_shooter, _weapon] call CBA_fnc_turretPathWeapon;
private _turretConfig = [_shooter, _turretPath] call CBA_fnc_getTurret; private _turretConfig = [_shooter, _turretPath] call CBA_fnc_getTurret;
@ -41,13 +41,6 @@ _attackProfileStateParams set [1, false]; // _wireCut
_attackProfileStateParams set [2, [0, 0, 0]]; // _randomVector _attackProfileStateParams set [2, [0, 0, 0]]; // _randomVector
_attackProfileStateParams set [3, _crosshairOffset]; // crosshair offset _attackProfileStateParams set [3, _crosshairOffset]; // crosshair offset
_attackProfileStateParams set [4, _maxDistanceSqr]; // max distance squared used for wire cut _attackProfileStateParams set [4, _maxDistanceSqr]; // max distance squared used for wire cut
_attackProfileStateParams set [5, _wireCutSource]; _attackProfileStateParams set [5, _minDistanceSqr];
_attackProfileStateParams set [6, _wireCutSource];
private _memoryPointGunnerOptics = getText(_turretConfig >> "memoryPointGunnerOptics");
private _animationSourceBody = getText(_turretConfig >> "animationSourceBody");
private _animationSourceGun = getText(_turretConfig >> "animationSourceGun");
_seekerStateParams set [0, _memoryPointGunnerOptics];
_seekerStateParams set [1, _animationSourceBody];
_seekerStateParams set [2, _animationSourceGun];
_seekerStateParams set [3, _distanceAheadOfMissile];

View File

@ -55,7 +55,8 @@ private _seekerTargetPos = [[0,0,0], _args, _seekerStateParams, _lastKnownPosSta
private _profileAdjustedTargetPos = [_seekerTargetPos, _args, _attackProfileStateParams] call FUNC(doAttackProfile); private _profileAdjustedTargetPos = [_seekerTargetPos, _args, _attackProfileStateParams] call FUNC(doAttackProfile);
// If we have no seeker target, then do not change anything // If we have no seeker target, then do not change anything
if (!(_profileAdjustedTargetPos isEqualTo [0,0,0])) then { // If there is no deflection on the missile, this cannot change and therefore is redundant. Avoid calculations for missiles without any deflection
if ((_minDeflection != 0 || {_maxDeflection != 0}) && {!(_profileAdjustedTargetPos isEqualTo [0,0,0])}) then {
private _targetVector = _projectilePos vectorFromTo _profileAdjustedTargetPos; private _targetVector = _projectilePos vectorFromTo _profileAdjustedTargetPos;
private _adjustVector = _targetVector vectorDiff (vectorDir _projectile); private _adjustVector = _targetVector vectorDiff (vectorDir _projectile);

View File

@ -112,19 +112,30 @@ private _args = [_this,
[ [
getNumber ( _config >> "seekerAngle" ), getNumber ( _config >> "seekerAngle" ),
getNumber ( _config >> "seekerAccuracy" ), getNumber ( _config >> "seekerAccuracy" ),
getNumber ( _config >> "seekerMaxRange" ) getNumber ( _config >> "seekerMaxRange" ),
getNumber ( _config >> "seekerMinRange" )
], ],
[ diag_tickTime, [], [], _lastKnownPosState] [ diag_tickTime, [], [], _lastKnownPosState]
]; ];
private _onFiredFunc = getText (configFile >> QGVAR(SeekerTypes) >> _seekerType >> "onFired");
// Run the "onFired" function passing the full guidance args array
private _onFiredFunc = getText (_config >> "onFired");
TRACE_1("",_onFiredFunc); TRACE_1("",_onFiredFunc);
if (_onFiredFunc != "") then { if (_onFiredFunc != "") then {
_args call (missionNamespace getVariable _onFiredFunc); _args call (missionNamespace getVariable _onFiredFunc);
}; };
_onFiredFunc = getText (configFile >> QGVAR(AttackProfiles) >> _attackProfile >> "onFired");
TRACE_1("",_onFiredFunc);
if (_onFiredFunc != "") then {
_args call (missionNamespace getVariable _onFiredFunc);
};
// Run the "onFired" function passing the full guidance args array
_onFiredFunc = getText (_config >> "onFired");
TRACE_1("",_onFiredFunc);
if (_onFiredFunc != "") then {
_args call (missionNamespace getVariable _onFiredFunc);
};
// Reverse: // Reverse:
// _args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"]; // _args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
@ -134,24 +145,6 @@ if (_onFiredFunc != "") then {
// _stateParams params ["_lastRunTime", "_seekerStateParams", "_attackProfileStateParams", "_lastKnownPosState"]; // _stateParams params ["_lastRunTime", "_seekerStateParams", "_attackProfileStateParams", "_lastKnownPosState"];
// _seekerParams params ["_seekerAngle", "_seekerAccuracy", "_seekerMaxRange"]; // _seekerParams params ["_seekerAngle", "_seekerAccuracy", "_seekerMaxRange"];
// Hand off to the guiding unit. We just use local player so local PFH fires for now
// Laser code needs to give us a shooter for LOBL, or the seeker unit needs to be able to shift locality
// Based on its homing laser
// Lasers need to be handled in a special LOAL/LOBL case
//if (isPlayer _shooter) then {
// private _guidingUnit = ACE_player;
//
// if (local _guidingUnit) then {
// [FUNC(guidancePFH), 0, _args ] call CBA_fnc_addPerFrameHandler;
// } else {
// [QGVAR(handoff), [_guidingUnit, _args] ] call FUNC(doHandoff);
// };
//} else {
// [FUNC(guidancePFH), 0, _args ] call CBA_fnc_addPerFrameHandler;
//};
[FUNC(guidancePFH), 0, _args ] call CBA_fnc_addPerFrameHandler; [FUNC(guidancePFH), 0, _args ] call CBA_fnc_addPerFrameHandler;

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

View File

@ -0,0 +1,80 @@
---
layout: wiki
title: M47 Dragon Missile
description: M47 Dragon
group: feature
category: equipment
parent: wiki
mod: ace
version:
major: 3
minor: 13
patch: 0
---
## 1. Overview
### 1.1 Guidance
The M47 Dragon is a wire-guided SACLOS missile with a unique manuever system. It has a series of charges along the missile that fire every third of a second to adjust the missile on course
### 1.2 Attack profiles
The missile requires line of sight to the target at all times. Keep your crosshair on the target as the missile cruises toward it until impact.
If you lose line of sight the missile will stop tracking toward your crosshair and will fly on its current trajectory. You can regain control if the missile re-enters line of sight.
If the missile exceeds its maximum range the wire will snap and it will fly off in a random direction.
The missiles manuever system causes inaccuracy that cannot be corrected for by the gunner. This means that the risk of missing increases as range goes up
## 2. Usage
### 2.1 Placement
- Ensure that you have the M47 Super-Dragon launcher as well as the SU-36/P sighting unit
- Use self interaction <kbd>Ctrl</kbd>+<kbd>&nbsp;Win</kbd> (ACE3 default key bind `Self Interaction Key`)
- Select 'Place Tripod'
- Interact with the missile <kbd>&nbsp;Win</kbd> (ACE3 default key bind `Interaction Key`)
- Select 'Attach Sight'
- Get into the launcher
- Point at target
- Fire
### 2.2 Tear Down
- Interact with the missile <kbd>&nbsp;Win</kbd> (ACE3 default key bind `Interaction Key`)
- Select 'Disassemble'
- Look to the right of the launcher and pick up the sighting unit
- Move on
## 3. Sight Ranging
The Dragon gunners use the stadia lines in the daysight to determine if a target falls within range. Moving and stationary vehicles may present flank, oblique, and frontal or rear targets (Figure 1).
At maximum range (1,500 meters), a 7-meter (23-foot) long target completely fills the area between the stadia lines and exceeds the stadia lines at a closer range.
**Figure 1. Frontal, oblique, and flank targets**
<img src="{{ site.baseurl }}/img/wiki/feature/m47_fro_obl_fla.png" width="1400" height="452" alt="Frontal, Oblique, and Flank targets" />
### 3.1 **Flanking Targets (Full Stadia)**
Adjust the sight picture by moving the launcher so the target centers between the stadia lines (Figure 2).
**Figure 2. Range determination for flank target.**
<img src="{{ site.baseurl }}/img/wiki/feature/m47_flank.png" width="1400" height="331" alt="Frontal, Oblique, and Flank targets" />
### 3.2 **Oblique Targets**
If you can see more of the flank, use the full-stadia method (Figure 3.1). The vehicle should appear to fill the area between the stadia lines. If you see more of the front or rear, use the half-stadia method (Figure 3.2). The track of the vehicle should fit between one stadia line and the center.
**Figure 3.1. Range determination for oblique target, more flank visible**
<img src="{{ site.baseurl }}/img/wiki/feature/m47_oblique_45.png" width="1400" height="408" alt="Frontal, Oblique, and Flank targets" />
**Figure 3.2. Range determination for oblique target, more front or rear visible**
<img src="{{ site.baseurl }}/img/wiki/feature/m47_oblique_60.png" width="1400" height="331" alt="Frontal, Oblique, and Flank targets" />
### 3.3 **Frontal (Head-On) or Rear (Going Away, Half-Stadia) Targets**
Adjust the sight picture by moving the launcher to align the vertical cross hair and one of the stadia lines on the target (Figure 4)
**Figure 4. Range determination for frontal or rear target.**
<img src="{{ site.baseurl }}/img/wiki/feature/m47_frontal.png" width="1400" height="357" alt="Frontal, Oblique, and Flank targets" />
## 4. Dependencies
{% include dependencies_list.md component="dragon" %}