mirror of
https://github.com/mostlikely4r/construction-mod.git
synced 2026-01-19 19:24:44 +00:00
2076 lines
61 KiB
C#
2076 lines
61 KiB
C#
|
|
|
|
// deployable objects script
|
|
//
|
|
// remote pulse sensor, remote motion sensor, remote turrets (indoor
|
|
// and outdoor), remote inventory station, remote ammo station
|
|
// Note: cameras are treated as grenades, not "regular" deployables
|
|
|
|
$Host::CRCTextures = 0;
|
|
$TurretIndoorSpaceRadius = 20; // deployed turrets must be this many meters apart
|
|
$InventorySpaceRadius = 20; // deployed inventory must be this many meters apart
|
|
$TurretIndoorSphereRadius = 50; // radius for turret frequency check
|
|
$TurretIndoorMaxPerSphere = 4; // # of turrets allowed in above radius
|
|
|
|
$TurretOutdoorSpaceRadius = 25; // deployed turrets must be this many meters apart
|
|
$TurretOutdoorSphereRadius = 60; // radius for turret frequency check
|
|
$TurretOutdoorMaxPerSphere = 4; // # of turrets allowed in above radius
|
|
|
|
$TeamDeployableMax[InventoryDeployable] = 5;
|
|
$TeamDeployableMax[TurretIndoorDeployable] = 10;
|
|
$TeamDeployableMax[TurretOutdoorDeployable] = 10;
|
|
$TeamDeployableMax[PulseSensorDeployable] = 15;
|
|
$TeamDeployableMax[MotionSensorDeployable] = 15;
|
|
|
|
$TeamDeployableMax[LargeInventoryDeployable] = 10;
|
|
$TeamDeployableMax[GeneratorDeployable] = 5;
|
|
$TeamDeployableMax[SolarPanelDeployable] = 15;
|
|
$TeamDeployableMax[SwitchDeployable] = 10;
|
|
$TeamDeployableMax[MediumSensorDeployable] = 4;
|
|
$TeamDeployableMax[LargeSensorDeployable] = 2;
|
|
$TeamDeployableMax[WallDeployable] = 1000;
|
|
$TeamDeployableMax[FloorDeployable] = 1000;
|
|
$TeamDeployableMax[wWallDeployable] = 1000;
|
|
$TeamDeployableMax[SpineDeployable] = 1000;
|
|
$TeamDeployableMax[mSpineDeployable] = 1000;
|
|
$TeamDeployableMax[JumpadDeployable] = 50;
|
|
$TeamDeployableMax[EscapePodDeployable] = 5;
|
|
$TeamDeployableMax[EnergizerDeployable] = 50;
|
|
$TeamDeployableMax[TreeDeployable] = 50;
|
|
$TeamDeployableMax[CrateDeployable] = 250;
|
|
$TeamDeployableMax[DecorationDeployable] = 100;
|
|
$TeamDeployableMax[LogoProjectorDeployable] = 10;
|
|
$TeamDeployableMax[LightDeployable] = 50;
|
|
$TeamDeployableMax[TripwireDeployable] = 50;
|
|
$TeamDeployableMax[ForceFieldDeployable] = 100;
|
|
$TeamDeployableMax[GravityFieldDeployable] = 30;
|
|
$TeamDeployableMax[TelePadPack] = 50;
|
|
$TeamDeployableMax[DoorDeployable] = 1000;
|
|
|
|
$TeamDeployableMax[TurretBasePack] = 8;
|
|
$TeamDeployableMax[TurretLaserDeployable] = 10;
|
|
$TeamDeployableMax[DiscTurretDeployable] = 10;
|
|
$TeamDeployableMax[TurretMissileRackDeployable] = 10;
|
|
|
|
//This could also be in "pack".cs but what the heck
|
|
//[most]
|
|
$TeamDeployableMax[TurretMpm_Anti_Deployable] = 40;
|
|
$TeamDeployableMax[VehiclePadPack] = 40;
|
|
$TeamDeployableMax[EmitterDepPack] = 50;
|
|
$TeamDeployableMax[AudioDepPack] = 50;
|
|
$TeamDeployableMax[DispenserDepPack] = 50;
|
|
$TeamDeployableMax[MPM_BeaconPack] = 50;
|
|
$TeamDeployableMax[DetonationDepPack] = 5;
|
|
//noone cares
|
|
$TeamDeployableMax[MpmFuelPack] = 1;
|
|
$TeamDeployableMax[MpmAmmoPack] = 1;
|
|
|
|
//[most]
|
|
|
|
$TeamDeployableMin[TurretIndoorDeployable] = 4;
|
|
$TeamDeployableMin[TurretOutdoorDeployable] = 4;
|
|
$TeamDeployableMin[TurretBasePack] = 4;
|
|
$TeamDeployableMin[TurretLaserDeployable] = 5;
|
|
$TeamDeployableMin[DiscTurretDeployable] = 4;
|
|
$TeamDeployableMin[TurretMissileRackDeployable] = 4;
|
|
|
|
//[most]
|
|
$TeamDeployableMin[TurretMpm_Anti_Deployable] = 40;
|
|
$TeamDeployableMin[VehiclePadPack] = 40;
|
|
$TeamDeployableMin[EmitterDepPack] = 50;
|
|
$TeamDeployableMin[AudioDepPack] = 50;
|
|
$TeamDeployableMin[DispenserDepPack] = 50;
|
|
$TeamDeployableMin[MPM_BeaconPack] = 50;
|
|
$TeamDeployableMin[DetonationDepPack] = 5;
|
|
//noone cares
|
|
$TeamDeployableMin[MpmFuelPack] = 1;
|
|
$TeamDeployableMin[MpmAmmoPack] = 1;
|
|
|
|
//[most]
|
|
|
|
$NotDeployableReason::None = 0;
|
|
$NotDeployableReason::MaxDeployed = 1;
|
|
$NotDeployableReason::NoSurfaceFound = 2;
|
|
$NotDeployableReason::SlopeTooGreat = 3;
|
|
$NotDeployableReason::SelfTooClose = 4;
|
|
$NotDeployableReason::ObjectTooClose = 5;
|
|
$NotDeployableReason::NoTerrainFound = 6;
|
|
$NotDeployableReason::NoInteriorFound = 7;
|
|
$NotDeployableReason::TurretTooClose = 8;
|
|
$NotDeployableReason::TurretSaturation = 9;
|
|
$NotDeployableReason::SurfaceTooNarrow = 10;
|
|
$NotDeployableReason::InventoryTooClose = 11;
|
|
|
|
$MinDeployableDistance = 2.5;
|
|
$MaxDeployableDistance = 5.0; //meters from body
|
|
|
|
// --------------------------------------------
|
|
// effect datablocks
|
|
// --------------------------------------------
|
|
|
|
datablock EffectProfile(TurretDeployEffect)
|
|
{
|
|
effectname = "packs/generic_deploy";
|
|
minDistance = 2.5;
|
|
maxDistance = 5.0;
|
|
};
|
|
|
|
datablock EffectProfile(SensorDeployEffect)
|
|
{
|
|
effectname = "powered/sensor_activate";
|
|
minDistance = 2.5;
|
|
maxDistance = 5.0;
|
|
};
|
|
|
|
datablock EffectProfile(MotionSensorDeployEffect)
|
|
{
|
|
effectname = "powered/motion_sensor_activate";
|
|
minDistance = 2.5;
|
|
maxDistance = 5.0;
|
|
};
|
|
|
|
datablock EffectProfile(StationDeployEffect)
|
|
{
|
|
effectname = "packs/inventory_deploy";
|
|
minDistance = 2.5;
|
|
maxDistance = 5.0;
|
|
};
|
|
|
|
// --------------------------------------------
|
|
// sound datablocks
|
|
// --------------------------------------------
|
|
|
|
datablock AudioProfile(TurretDeploySound)
|
|
{
|
|
fileName = "fx/packs/turret_place.wav";
|
|
description = AudioClose3d;
|
|
preload = true;
|
|
effect = TurretDeployEffect;
|
|
};
|
|
|
|
datablock AudioProfile(DSound)
|
|
{
|
|
filename = "fx/weapons/plasma_rifle_activate.wav";
|
|
//filename = "fx/packs/repair_use.wav";
|
|
description = AudioClose3d;
|
|
preload = true;
|
|
};
|
|
|
|
datablock AudioProfile(SensorDeploySound)
|
|
{
|
|
fileName = "fx/powered/sensor_activate.wav";
|
|
description = AudioClose3d;
|
|
preload = true;
|
|
effect = SensorDeployEffect;
|
|
// z0dd - ZOD - Durt, 6/24/02. Eh? This shouldn't be in here.
|
|
//effect = MotionSensorDeployEffect;
|
|
};
|
|
|
|
datablock AudioProfile(MotionSensorDeploySound)
|
|
{
|
|
fileName = "fx/powered/motion_sensor_activate.wav";
|
|
description = AudioClose3d;
|
|
preload = true;
|
|
// z0dd - ZOD - Durt, 6/24/02. This should be in here.
|
|
effect = MotionSensorDeployEffect;
|
|
};
|
|
|
|
datablock AudioProfile(StationDeploySound)
|
|
{
|
|
fileName = "fx/packs/inventory_deploy.wav";
|
|
description = AudioClose3d;
|
|
preload = true;
|
|
effect = StationDeployEffect;
|
|
};
|
|
|
|
// --------------------------------------------
|
|
// deployable debris definition
|
|
|
|
datablock DebrisData( DeployableDebris )
|
|
{
|
|
explodeOnMaxBounce = true;
|
|
|
|
elasticity = 0.40;
|
|
friction = 0.5;
|
|
|
|
lifetime = 200.0;
|
|
lifetimeVariance = 5.0;
|
|
|
|
minSpinSpeed = 60;
|
|
maxSpinSpeed = 600;
|
|
|
|
numBounces = 10;
|
|
bounceVariance = 1;
|
|
|
|
staticOnMaxBounce = true;
|
|
|
|
useRadiusMass = true;
|
|
baseRadius = 20;
|
|
|
|
velocity = 5.0;
|
|
velocityVariance = 2.5;
|
|
|
|
};
|
|
|
|
|
|
// --------------------------------------------
|
|
// deployable inventory station
|
|
|
|
datablock StaticShapeData(DeployedStationInventory) : StaticShapeDamageProfile
|
|
{
|
|
className = Station;
|
|
shapeFile = "deploy_inventory.dts";
|
|
maxDamage = 0.70;
|
|
destroyedLevel = 0.70;
|
|
disabledLevel = 0.42;
|
|
explosion = DeployablesExplosion;
|
|
expDmgRadius = 8.0;
|
|
expDamage = 0.35;
|
|
expImpulse = 500.0;
|
|
|
|
dynamicType = $TypeMasks::StationObjectType;
|
|
isShielded = true;
|
|
energyPerDamagePoint = 110;
|
|
maxEnergy = 50;
|
|
rechargeRate = 0.20;
|
|
renderWhenDestroyed = false;
|
|
doesRepair = true;
|
|
|
|
deployedObject = true;
|
|
|
|
cmdCategory = "DSupport";
|
|
cmdIcon = CMDStationIcon;
|
|
cmdMiniIconName = "commander/MiniIcons/com_inventory_grey";
|
|
targetNameTag = 'Deployable';
|
|
targetTypeTag = 'Station';
|
|
|
|
debrisShapeName = "debris_generic_small.dts";
|
|
debris = DeployableDebris;
|
|
heatSignature = 0;
|
|
};
|
|
|
|
datablock ShapeBaseImageData(InventoryDeployableImage)
|
|
{
|
|
mass = 15;
|
|
emap = true;
|
|
|
|
shapeFile = "pack_deploy_inventory.dts";
|
|
item = InventoryDeployable;
|
|
mountPoint = 1;
|
|
offset = "0 0 0";
|
|
deployed = DeployedStationInventory;
|
|
heatSignature = 0;
|
|
|
|
stateName[0] = "Idle";
|
|
stateTransitionOnTriggerDown[0] = "Activate";
|
|
|
|
stateName[1] = "Activate";
|
|
stateScript[1] = "onActivate";
|
|
stateTransitionOnTriggerUp[1] = "Idle";
|
|
|
|
isLarge = true;
|
|
maxDepSlope = 30;
|
|
deploySound = StationDeploySound;
|
|
|
|
flatMinDeployDis = 1.0;
|
|
flatMaxDeployDis = 5.0;
|
|
|
|
minDeployDis = 2.5;
|
|
maxDeployDis = 5.0;
|
|
};
|
|
|
|
datablock ItemData(InventoryDeployable)
|
|
{
|
|
className = Pack;
|
|
catagory = "Deployables";
|
|
shapeFile = "pack_deploy_inventory.dts";
|
|
mass = 3.0;
|
|
elasticity = 0.2;
|
|
friction = 0.6;
|
|
pickupRadius = 1;
|
|
rotate = false;
|
|
image = "InventoryDeployableImage";
|
|
pickUpName = "an inventory pack";
|
|
heatSignature = 0;
|
|
|
|
computeCRC = true;
|
|
emap = true;
|
|
|
|
};
|
|
|
|
// --------------------------------------------
|
|
// deployable motion sensor
|
|
|
|
datablock SensorData(DeployMotionSensorObj)
|
|
{
|
|
detects = true;
|
|
detectsUsingLOS = true;
|
|
detectsActiveJammed = false;
|
|
detectsPassiveJammed = true;
|
|
detectsCloaked = true;
|
|
detectionPings = false;
|
|
detectMinVelocity = 2;
|
|
detectRadius = 60;
|
|
};
|
|
|
|
datablock StaticShapeData(DeployedMotionSensor) : StaticShapeDamageProfile
|
|
{
|
|
className = Sensor;
|
|
shapeFile = "deploy_sensor_motion.dts";
|
|
maxDamage = 0.6;
|
|
destroyedLevel = 0.6;
|
|
disabledLevel = 0.4;
|
|
explosion = DeployablesExplosion;
|
|
dynamicType = $TypeMasks::SensorObjectType;
|
|
|
|
deployedObject = true;
|
|
|
|
cmdCategory = "DSupport";
|
|
cmdIcon = CMDSensorIcon;
|
|
cmdMiniIconName = "commander/MiniIcons/com_deploymotionsensor";
|
|
targetNameTag = 'Deployable Motion';
|
|
targetTypeTag = 'Sensor';
|
|
sensorData = DeployMotionSensorObj;
|
|
sensorRadius = DeployMotionSensorObj.detectRadius;
|
|
sensorColor = "9 136 255";
|
|
deployAmbientThread = true;
|
|
|
|
debrisShapeName = "debris_generic_small.dts";
|
|
debris = DeployableDebris;
|
|
heatSignature = 0;
|
|
};
|
|
|
|
datablock ShapeBaseImageData(MotionSensorDeployableImage)
|
|
{
|
|
shapeFile = "pack_deploy_sensor_motion.dts";
|
|
item = MotionSensorDeployable;
|
|
mountPoint = 1;
|
|
offset = "0 0 0";
|
|
deployed = DeployedMotionSensor;
|
|
|
|
stateName[0] = "Idle";
|
|
stateTransitionOnTriggerDown[0] = "Activate";
|
|
|
|
stateName[1] = "Activate";
|
|
stateScript[1] = "onActivate";
|
|
stateTransitionOnTriggerUp[1] = "Idle";
|
|
|
|
maxDepSlope = 360;
|
|
deploySound = MotionSensorDeploySound;
|
|
emap = true;
|
|
heatSignature = 1;
|
|
|
|
minDeployDis = 0.5;
|
|
maxDeployDis = 5.0; //meters from body
|
|
};
|
|
|
|
datablock ItemData(MotionSensorDeployable)
|
|
{
|
|
className = Pack;
|
|
catagory = "Deployables";
|
|
shapeFile = "pack_deploy_sensor_motion.dts";
|
|
mass = 2.0;
|
|
elasticity = 0.2;
|
|
friction = 0.6;
|
|
pickupRadius = 1;
|
|
rotate = false;
|
|
image = "MotionSensorDeployableImage";
|
|
pickUpName = "a motion sensor pack";
|
|
|
|
computeCRC = true;
|
|
emap = true;
|
|
heatSignature = 0;
|
|
|
|
//maxSensors = 3;
|
|
maxSensors = 2;
|
|
};
|
|
|
|
// --------------------------------------------
|
|
// deployable pulse sensor
|
|
|
|
datablock SensorData(DeployPulseSensorObj)
|
|
{
|
|
detects = true;
|
|
detectsUsingLOS = true;
|
|
detectsPassiveJammed = false;
|
|
detectsCloaked = false;
|
|
detectionPings = true;
|
|
detectRadius = 150;
|
|
};
|
|
|
|
datablock StaticShapeData(DeployedPulseSensor) : StaticShapeDamageProfile
|
|
{
|
|
className = Sensor;
|
|
shapeFile = "deploy_sensor_pulse.dts";
|
|
maxDamage = 0.6;
|
|
destroyedLevel = 0.6;
|
|
disabledLevel = 0.4;
|
|
explosion = DeployablesExplosion;
|
|
dynamicType = $TypeMasks::SensorObjectType;
|
|
|
|
deployedObject = true;
|
|
|
|
cmdCategory = "DSupport";
|
|
cmdIcon = CMDSensorIcon;
|
|
cmdMiniIconName = "commander/MiniIcons/com_deploypulsesensor";
|
|
targetNameTag = 'Deployable';
|
|
targetTypeTag = 'Pulse Sensor';
|
|
sensorData = DeployPulseSensorObj;
|
|
sensorRadius = DeployPulseSensorObj.detectRadius;
|
|
sensorColor = "255 194 9";
|
|
deployAmbientThread = true;
|
|
|
|
debrisShapeName = "debris_generic_small.dts";
|
|
debris = DeployableDebris;
|
|
heatSignature = 0;
|
|
};
|
|
|
|
datablock ShapeBaseImageData(PulseSensorDeployableImage)
|
|
{
|
|
shapeFile = "pack_deploy_sensor_pulse.dts";
|
|
item = PulseSensorDeployable;
|
|
mountPoint = 1;
|
|
offset = "0 0 0";
|
|
deployed = DeployedPulseSensor;
|
|
|
|
stateName[0] = "Idle";
|
|
stateTransitionOnTriggerDown[0] = "Activate";
|
|
|
|
stateName[1] = "Activate";
|
|
stateScript[1] = "onActivate";
|
|
stateTransitionOnTriggerUp[1] = "Idle";
|
|
deploySound = SensorDeploySound;
|
|
|
|
maxDepSlope = 40;
|
|
emap = true;
|
|
heatSignature = 0;
|
|
|
|
minDeployDis = 0.5;
|
|
maxDeployDis = 5.0; //meters from body
|
|
};
|
|
|
|
datablock ItemData(PulseSensorDeployable)
|
|
{
|
|
className = Pack;
|
|
catagory = "Deployables";
|
|
shapeFile = "pack_deploy_sensor_pulse.dts";
|
|
mass = 2.0;
|
|
elasticity = 0.2;
|
|
friction = 0.6;
|
|
pickupRadius = 1;
|
|
rotate = false;
|
|
image = "PulseSensorDeployableImage";
|
|
pickUpName = "a pulse sensor pack";
|
|
|
|
computeCRC = true;
|
|
emap = true;
|
|
|
|
maxSensors = 2;
|
|
};
|
|
|
|
// --------------------------------------------
|
|
// deployable outdoor turret
|
|
|
|
datablock ShapeBaseImageData(TurretOutdoorDeployableImage)
|
|
{
|
|
mass = 15;
|
|
|
|
shapeFile = "pack_deploy_turreto.dts";
|
|
item = TurretOutdoorDeployable;
|
|
mountPoint = 1;
|
|
offset = "0 0 0";
|
|
deployed = TurretDeployedOutdoor;
|
|
|
|
stateName[0] = "Idle";
|
|
stateTransitionOnTriggerDown[0] = "Activate";
|
|
|
|
stateName[1] = "Activate";
|
|
stateScript[1] = "onActivate";
|
|
stateTransitionOnTriggerUp[1] = "Idle";
|
|
|
|
maxDamage = 4.5;
|
|
destroyedLevel = 4.5;
|
|
disabledLevel = 4.0;
|
|
|
|
isLarge = true;
|
|
emap = true;
|
|
|
|
maxDepSlope = 40;
|
|
deploySound = TurretDeploySound;
|
|
|
|
minDeployDis = 0.5;
|
|
maxDeployDis = 5.0; //meters from body
|
|
};
|
|
|
|
datablock ItemData(TurretOutdoorDeployable)
|
|
{
|
|
className = Pack;
|
|
catagory = "Deployables";
|
|
shapeFile = "pack_deploy_turreto.dts";
|
|
mass = 3.0;
|
|
elasticity = 0.2;
|
|
friction = 0.6;
|
|
pickupRadius = 1;
|
|
rotate = false;
|
|
image = "TurretOutdoorDeployableImage";
|
|
pickUpName = "a landspike turret pack";
|
|
|
|
computeCRC = true;
|
|
emap = true;
|
|
|
|
};
|
|
|
|
// --------------------------------------------
|
|
// deployable indoor turret (3 varieties -- floor, wall and ceiling)
|
|
|
|
datablock ShapeBaseImageData(TurretIndoorDeployableImage)
|
|
{
|
|
mass = 15;
|
|
|
|
shapeFile = "pack_deploy_turreti.dts";
|
|
item = TurretIndoorDeployable;
|
|
mountPoint = 1;
|
|
offset = "0 0 0";
|
|
|
|
stateName[0] = "Idle";
|
|
stateTransitionOnTriggerDown[0] = "Activate";
|
|
|
|
stateName[1] = "Activate";
|
|
stateScript[1] = "onActivate";
|
|
stateTransitionOnTriggerUp[1] = "Idle";
|
|
|
|
isLarge = true;
|
|
emap = true;
|
|
|
|
maxDepSlope = 360;
|
|
deploySound = TurretDeploySound;
|
|
|
|
minDeployDis = 0.5;
|
|
maxDeployDis = 5.0; //meters from body
|
|
};
|
|
|
|
datablock ItemData(TurretIndoorDeployable)
|
|
{
|
|
className = Pack;
|
|
catagory = "Deployables";
|
|
shapeFile = "pack_deploy_turreti.dts";
|
|
mass = 3.0;
|
|
elasticity = 0.2;
|
|
friction = 0.6;
|
|
pickupRadius = 1;
|
|
rotate = false;
|
|
image = "TurretIndoorDeployableImage";
|
|
pickUpName = "a spider clamp turret pack";
|
|
|
|
computeCRC = true;
|
|
emap = true;
|
|
|
|
};
|
|
|
|
// --------------------------------------------
|
|
// miscellaneous yet handy functions
|
|
|
|
function posFromTransform(%transform)
|
|
{
|
|
// the first three words of an object's transform are the object's position
|
|
%position = getWord(%transform, 0) @ " " @ getWord(%transform, 1) @ " " @ getWord(%transform, 2);
|
|
return %position;
|
|
}
|
|
|
|
function rotFromTransform(%transform)
|
|
{
|
|
// the last four words of an object's transform are the object's rotation
|
|
%rotation = getWord(%transform, 3) @ " " @ getWord(%transform, 4) @ " " @ getWord(%transform, 5) @ " " @ getWord(%transform, 6);
|
|
return %rotation;
|
|
}
|
|
|
|
function posFromRaycast(%transform)
|
|
{
|
|
// the 2nd, 3rd, and 4th words returned from a successful raycast call are the position of the point
|
|
%position = getWord(%transform, 1) @ " " @ getWord(%transform, 2) @ " " @ getWord(%transform, 3);
|
|
return %position;
|
|
}
|
|
|
|
function normalFromRaycast(%transform)
|
|
{
|
|
// the 5th, 6th and 7th words returned from a successful raycast call are the normal of the surface
|
|
%norm = getWord(%transform, 4) @ " " @ getWord(%transform, 5) @ " " @ getWord(%transform, 6);
|
|
return %norm;
|
|
}
|
|
|
|
function addToDeployGroup(%object)
|
|
{
|
|
// all deployables should go into a special group for AI purposes
|
|
%depGroup = nameToID("MissionCleanup/Deployables");
|
|
if (%depGroup <= 0) {
|
|
%depGroup = new SimGroup("Deployables");
|
|
MissionCleanup.add(%depGroup);
|
|
}
|
|
%depGroup.add(%object);
|
|
}
|
|
|
|
|
|
|
|
function Deployables::searchView(%obj, %searchRange, %mask)
|
|
{
|
|
// get the eye vector and eye transform of the player
|
|
%eyeVec = %obj.getEyeVector();
|
|
%eyeTrans = %obj.getEyeTransform();
|
|
|
|
// extract the position of the player's camera from the eye transform (first 3 words)
|
|
%eyePos = posFromTransform(%eyeTrans);
|
|
|
|
// normalize the eye vector
|
|
%nEyeVec = VectorNormalize(%eyeVec);
|
|
|
|
// scale (lengthen) the normalized eye vector according to the search range
|
|
%scEyeVec = VectorScale(%nEyeVec, %searchRange);
|
|
|
|
// add the scaled & normalized eye vector to the position of the camera
|
|
%eyeEnd = VectorAdd(%eyePos, %scEyeVec);
|
|
|
|
// %pack = %obj.getMountedImage($BackpackSlot);
|
|
|
|
//if (%pack.deployed.ClassName $= "mspine")
|
|
// {
|
|
// %mask2 = $TypeMasks::StaticObjectType;
|
|
// %searchResult = containerRayCast(%eyePos, %eyeEnd, %mask2, 0);
|
|
// if ((%searchResult) && (%searchResult.getType() & $TypeMasks::StaticObjectType))
|
|
// {
|
|
// if (%searchResult.getDataBlock().className $= "mspine")
|
|
// return %searchResult;
|
|
// else if (%searchResult.getDataBlock().className $= "spine")
|
|
// return %searchResult;
|
|
// else if (%searchResult.getDataBlock().className $= "Wall")
|
|
// return %searchResult;
|
|
// else if (%searchResult.getDataBlock().className $= "wWall")
|
|
// return %searchResult;
|
|
// else if (%searchResult.getDataBlock().className $= "item")
|
|
// return %searchResult;
|
|
// else if (%searchResult.getDataBlock().className $= "floor")
|
|
// return %searchResult;
|
|
// %searchResult = "";
|
|
// }
|
|
// }
|
|
|
|
// see if anything gets hit
|
|
%searchResult = containerRayCast(%eyePos, %eyeEnd, %mask, 0);
|
|
if (%searchResult)
|
|
%pos2 = getWords(%searchResult, 1, 3);
|
|
else
|
|
%pos2 = %eyeEnd;
|
|
%searchResult2 = containerRayCast(%eyePos, %pos2, $TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType, 0);
|
|
if (%searchResult2) {
|
|
if (%searchResult2.getDataBlock().className $= "wWall")
|
|
return %searchResult2;
|
|
else if (%searchResult2.getDataBlock().className $= "Wall")
|
|
return %searchResult2;
|
|
else if (%searchResult2.getDataBlock().className $= "spine")
|
|
return %searchResult2;
|
|
else if (%searchResult2.getDataBlock().className $= "mspine")
|
|
return %searchResult2;
|
|
else if (%searchResult2.getDataBlock().className $= "item")
|
|
return %searchResult2;
|
|
else if (%searchResult2.getDataBlock().className $= "floor")
|
|
return %searchResult2;
|
|
else if (%searchResult2.getDataBlock().className $= "tree")
|
|
return %searchResult2;
|
|
else if (%searchResult2.getDataBlock().className $= "crate")
|
|
return %searchResult2;
|
|
else if (%searchResult2.getDataBlock().className $= "decoration") {
|
|
if (%searchResult2.getDataBlock().getName() $= "DeployedDecoration6")
|
|
return %searchResult2;
|
|
else
|
|
return; // Don't deploy on or through other decorations, since there are problems with surface normals
|
|
}
|
|
else if (%searchResult2.getType() & $TypeMasks::ForceFieldObjectType)
|
|
return; // Don't deploy inside or through forcefields
|
|
}
|
|
return %searchResult;
|
|
}
|
|
|
|
//-----------------------//
|
|
// Deployable Procedures //
|
|
//-----------------------//
|
|
|
|
//-------------------------------------------------
|
|
function ShapeBaseImageData::testMaxDeployed(%item, %plyr) {
|
|
if (%item.item $= TurretOutdoorDeployable
|
|
|| %item.item $= TurretIndoorDeployable
|
|
|| %item.item $= TurretBasePack
|
|
|| %item.item $= TurretLaserDeployable
|
|
|| %item.item $= TurretMissileRackDeployable
|
|
|| %item.item $= TurretMpm_Anti_Deployable
|
|
|| %item.item $= DiscTurretDeployable)
|
|
%itemCount = countTurretsAllowed(%item.item);
|
|
else
|
|
%itemCount = $TeamDeployableMax[%item.item];
|
|
|
|
return $TeamDeployedCount[%plyr.team, %item.item] >= %itemCount;
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
function ShapeBaseImageData::testNoSurfaceInRange(%item, %plyr)
|
|
{
|
|
return ! Deployables::searchView(%plyr, $MaxDeployDistance, $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType);
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
function ShapeBaseImageData::testSlopeTooGreat(%item)
|
|
{
|
|
if (%item.surface)
|
|
{
|
|
return getTerrainAngle(%item.surfaceNrm) > %item.maxDepSlope;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
function ShapeBaseImageData::testSelfTooClose(%item, %plyr)
|
|
{
|
|
InitContainerRadiusSearch(%item.surfacePt, $MinDeployDistance, $TypeMasks::PlayerObjectType);
|
|
|
|
return containerSearchNext() == %plyr;
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
function ShapeBaseImageData::testObjectTooClose(%item) {
|
|
%mask = ($TypeMasks::VehicleObjectType | $TypeMasks::MoveableObjectType |
|
|
$TypeMasks::StaticShapeObjectType |
|
|
$TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType |
|
|
$TypeMasks::PlayerObjectType | $TypeMasks::TurretObjectType);
|
|
|
|
InitContainerRadiusSearch(%item.surfacePt,$MinDeployDistance,%mask);
|
|
|
|
// TODO - update this
|
|
while ((%test = containerSearchNext()) != 0) {
|
|
%className = %test.getDataBlock().className;
|
|
if (vectorDist(%item.surfacePt,%test.getPosition()) < $MinDeployDistance
|
|
&& %className !$= "Wall" && %className !$= "wWall" && %className !$= "spine" && %className !$= "mspine"
|
|
&& %className !$= "floor" && %className !$= "tree" && %className !$= "crate" && %className !$= "decoration"
|
|
&& %className !$= "light" && %className !$= "decontarget" && %className !$= "item"
|
|
&& %className !$= "pack" )
|
|
return %test;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
function TurretOutdoorDeployableImage::testNoTerrainFound(%item)
|
|
{
|
|
return %item.surface.getClassName() !$= TerrainBlock;
|
|
}
|
|
|
|
function ShapeBaseImageData::testNoTerrainFound(%item, %surface)
|
|
{
|
|
//don't check this for non-Landspike turret deployables
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
function TurretIndoorDeployableImage::testNoInteriorFound(%item) {
|
|
if (%item.surface.getType() & $TypeMasks::StaticShapeObjectType) {
|
|
%className = %item.surface.getDataBlock().className;
|
|
if (%className $= "Wall")
|
|
return 0;
|
|
else if (%className $= "wWall")
|
|
return 0;
|
|
else if (%className $= "spine")
|
|
return 0;
|
|
else if (%className $= "mspine")
|
|
return 0;
|
|
else if (%className $= "item")
|
|
return 0;
|
|
else if (%className $= "floor")
|
|
return 0;
|
|
else if (%className $= "tree")
|
|
return 0;
|
|
else if (%className $= "crate")
|
|
return 0;
|
|
else if (%className $= "decoration")
|
|
return 0;
|
|
}
|
|
return %item.surface.getClassName() !$= InteriorInstance;
|
|
}
|
|
|
|
function ShapeBaseImageData::testNoInteriorFound(%item, %surface)
|
|
{
|
|
//don't check this for non-Clasping turret deployables
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
function TurretIndoorDeployableImage::testHavePurchase(%item, %xform)
|
|
{
|
|
%footprintRadius = 0.34;
|
|
%collMask = $TypeMasks::InteriorObjectType;
|
|
return %item.deployed.checkDeployPurchase(%xform, %footprintRadius, %collMask);
|
|
}
|
|
|
|
function ShapeBaseImageData::testHavePurchase(%item, %xform)
|
|
{
|
|
//don't check this for non-Clasping turret deployables
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
function ShapeBaseImageData::testInventoryTooClose(%item, %plyr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
function InventoryDeployableImage::testInventoryTooClose(%item, %plyr)
|
|
{
|
|
InitContainerRadiusSearch(%item.surfacePt, $InventorySpaceRadius, $TypeMasks::StaticShapeObjectType);
|
|
|
|
// old function was only checking whether the first object found was a turret -- also wasn't checking
|
|
// which team the object was on
|
|
%turretInRange = false;
|
|
while((%found = containerSearchNext()) != 0)
|
|
{
|
|
%foundName = %found.getDataBlock().getName();
|
|
if ( (%foundName $= DeployedStationInventory) )
|
|
if (%found.team == %plyr.team)
|
|
{
|
|
%turretInRange = true;
|
|
break;
|
|
}
|
|
}
|
|
return %turretInRange;
|
|
}
|
|
|
|
|
|
// TODO - keep this up to date
|
|
function isDeployedTurret(%obj) {
|
|
%dataBlockName = %obj.getDataBlock().getName();
|
|
if ((%dataBlockName $= TurretDeployedFloorIndoor)
|
|
|| (%dataBlockName $= TurretDeployedWallIndoor)
|
|
|| (%dataBlockName $= TurretDeployedCeilingIndoor)
|
|
|| (%dataBlockName $= TurretDeployedOutdoor)
|
|
|| (%dataBlockName $= TurretDeployedBase)
|
|
|| (%dataBlockName $= LaserDeployed)
|
|
|| (%dataBlockName $= MissileRackTurretDeployed)
|
|
|| (%dataBlockName $= Mpm_anti_TurretDeployed)
|
|
|| (%dataBlockName $= DiscTurretDeployed))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
// TODO - keep this up to date
|
|
function isDeployableTurret(%item) {
|
|
if ((%item $= TurretIndoorDeployable)
|
|
|| (%item $= TurretOutdoorDeployable)
|
|
|| (%item $= TurretBasePack)
|
|
|| (%item $= TurretLaserDeployable)
|
|
|| (%item $= TurretMissileRackDeployable)
|
|
|| (%item $= TurretMpm_anti_Deployable)
|
|
|| (%item $= DiscTurretDeployable))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
function TurretIndoorDeployableImage::testTurretTooClose(%item, %plyr) {
|
|
InitContainerRadiusSearch(%item.surfacePt, $TurretIndoorSpaceRadius, $TypeMasks::StaticShapeObjectType);
|
|
// old function was only checking whether the first object found was a turret -- also wasn't checking
|
|
// which team the object was on
|
|
%turretInRange = false;
|
|
while((%found = containerSearchNext()) != 0) {
|
|
if (isDeployedTurret(%found)) {
|
|
if (%found.team == %plyr.team) {
|
|
%turretInRange = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return %turretInRange;
|
|
}
|
|
|
|
function TurretOutdoorDeployableImage::testTurretTooClose(%item, %plyr) {
|
|
InitContainerRadiusSearch(%item.surfacePt, $TurretOutdoorSpaceRadius, $TypeMasks::StaticShapeObjectType);
|
|
// old function was only checking whether the first object found was a turret -- also wasn't checking
|
|
// which team the object was on
|
|
%turretInRange = false;
|
|
while((%found = containerSearchNext()) != 0) {
|
|
if (isDeployedTurret(%found)) {
|
|
if (%found.team == %plyr.team) {
|
|
%turretInRange = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return %turretInRange;
|
|
}
|
|
|
|
function TurretDeployableImage::testTurretTooClose(%item, %plyr) {
|
|
return TurretOutdoorDeployableImage::testTurretTooClose(%item, %plyr);
|
|
}
|
|
|
|
function TurretLaserDeployableImage::testTurretTooClose(%item, %plyr) {
|
|
return TurretIndoorDeployableImage::testTurretTooClose(%item, %plyr);
|
|
}
|
|
|
|
function TurretMissileRackDeployableImage::testTurretTooClose(%item, %plyr) {
|
|
return TurretOutdoorDeployableImage::testTurretTooClose(%item, %plyr);
|
|
}
|
|
|
|
|
|
function TurretMpm_Anti_DeployableImage::testTurretTooClose(%item, %plyr) {
|
|
return TurretOutdoorDeployableImage::testTurretTooClose(%item, %plyr);
|
|
}
|
|
|
|
|
|
function DiscTurretDeployableImage::testTurretTooClose(%item, %plyr) {
|
|
return TurretOutdoorDeployableImage::testTurretTooClose(%item, %plyr);
|
|
}
|
|
|
|
function ShapeBaseImageData::testTurretTooClose(%item, %plyr)
|
|
{
|
|
//don't check this for non-turret deployables
|
|
}
|
|
|
|
//[most]
|
|
function ShapeBaseImageData::testSurfaceTooNarrow(%item,%surface)
|
|
{
|
|
//don't check this for non-v-pad deployables
|
|
}
|
|
//[most]
|
|
|
|
// TODO - keep this up to date
|
|
|
|
//-------------------------------------------------
|
|
function TurretIndoorDeployableImage::testTurretSaturation(%item) {
|
|
%highestDensity = 0;
|
|
InitContainerRadiusSearch(%item.surfacePt, $TurretIndoorSphereRadius, $TypeMasks::StaticShapeObjectType);
|
|
%found = containerSearchNext();
|
|
while(%found) {
|
|
if (isDeployedTurret(%found)) {
|
|
//found one
|
|
%numTurretsNearby++;
|
|
%nearbyDensity = testNearbyDensity(%found, $TurretIndoorSphereRadius);
|
|
if (%nearbyDensity > %highestDensity)
|
|
%highestDensity = %nearbyDensity;
|
|
}
|
|
%found = containerSearchNext();
|
|
}
|
|
if (%numTurretsNearby > %highestDensity)
|
|
%highestDensity = %numTurretsNearby;
|
|
return %highestDensity > $TurretIndoorMaxPerSphere;
|
|
}
|
|
|
|
function TurretOutdoorDeployableImage::testTurretSaturation(%item) {
|
|
%highestDensity = 0;
|
|
InitContainerRadiusSearch(%item.surfacePt, $TurretOutdoorSphereRadius, $TypeMasks::StaticShapeObjectType);
|
|
%found = containerSearchNext();
|
|
while(%found) {
|
|
if (isDeployedTurret(%found)) {
|
|
//found one
|
|
%numTurretsNearby++;
|
|
%nearbyDensity = testNearbyDensity(%found, $TurretOutdoorSphereRadius);
|
|
if (%nearbyDensity > %highestDensity)
|
|
%highestDensity = %nearbyDensity;
|
|
}
|
|
%found = containerSearchNext();
|
|
}
|
|
if (%numTurretsNearby > %highestDensity)
|
|
%highestDensity = %numTurretsNearby;
|
|
return %highestDensity > $TurretOutdoorMaxPerSphere;
|
|
}
|
|
|
|
function TurretDeployableImage::testTurretSaturation(%item, %plyr) {
|
|
return TurretOutdoorDeployableImage::testTurretSaturation(%item, %plyr);
|
|
}
|
|
|
|
function TurretLaserDeployableImage::testTurretSaturation(%item, %plyr) {
|
|
return TurretIndoorDeployableImage::testTurretSaturation(%item, %plyr);
|
|
}
|
|
|
|
function TurretMissileRackDeployableImage::testTurretSaturation(%item, %plyr) {
|
|
return TurretOutdoorDeployableImage::testTurretSaturation(%item, %plyr);
|
|
}
|
|
|
|
|
|
function TurretMpm_Anti_DeployableImage::testTurretSaturation(%item, %plyr) {
|
|
return TurretOutdoorDeployableImage::testTurretSaturation(%item, %plyr);
|
|
}
|
|
|
|
function DiscTurretDeployableImage::testTurretSaturation(%item, %plyr) {
|
|
return TurretOutdoorDeployableImage::testTurretSaturation(%item, %plyr);
|
|
}
|
|
|
|
function ShapeBaseImageData::testTurretSaturation(%item, %surfacePt)
|
|
{
|
|
//don't check this for non-turret deployables
|
|
}
|
|
|
|
function testNearbyDensity(%item, %radius) {
|
|
//this checks how many turrets are in adjacent spheres in case placing a new one overloads them.
|
|
%surfacePt = posFromTransform(%item.getTransform());
|
|
%turretCount = 0;
|
|
InitContainerRadiusSearch(%surfacePt, %radius, $TypeMasks::StaticShapeObjectType);
|
|
%found = containerSearchNext();
|
|
while(%found) {
|
|
if (isDeployedTurret(%found))
|
|
%turretCount++;
|
|
%found = containerSearchNext();
|
|
}
|
|
return %turretCount;
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
//if this function, or any of the included tests are changed, those changes need to be reflected in function:
|
|
//AIODeployEquipment::weight(%this, %client, %level), found in aiObjectives.cs --tinman
|
|
|
|
function ShapeBaseImageData::testInvalidDeployConditions(%item, %plyr, %slot) {
|
|
cancel(%plyr.deployCheckThread);
|
|
%disqualified = $NotDeployableReason::None; //default
|
|
$MaxDeployDistance = %item.maxDeployDis;
|
|
$MinDeployDistance = %item.minDeployDis;
|
|
|
|
%pack = %plyr.getMountedImage($BackpackSlot);
|
|
|
|
if (%pack.deployed.className $= "decoration") {
|
|
if (%plyr.packSet == 6)
|
|
$MinDeployDistance = 2;
|
|
if (%plyr.packSet == 10)
|
|
$MinDeployDistance = 5;
|
|
if (%plyr.packSet == 11)
|
|
$MinDeployDistance = 4;
|
|
}
|
|
|
|
%surface = Deployables::searchView(%plyr,
|
|
$MaxDeployDistance,
|
|
($TypeMasks::TerrainObjectType |
|
|
$TypeMasks::InteriorObjectType |
|
|
$TypeMasks::StaticShapeObjectType));
|
|
if (%surface) {
|
|
%surfacePt = posFromRaycast(%surface);
|
|
%surfaceNrm = normalFromRaycast(%surface);
|
|
|
|
// Check that point to see if anything is obstructing it...
|
|
%eyeTrans = %plyr.getEyeTransform();
|
|
%eyePos = posFromTransform(%eyeTrans);
|
|
|
|
%searchResult = containerRayCast(%eyePos, %surfacePt, -1, %plyr);
|
|
if (!%searchResult) {
|
|
%item.surface = %surface;
|
|
%item.surfacePt = %surfacePt;
|
|
%item.surfaceNrm = %surfaceNrm;
|
|
}
|
|
else {
|
|
if (checkPositions(%surfacePT, posFromRaycast(%searchResult))) {
|
|
%item.surface = %surface;
|
|
%item.surfacePt = %surfacePt;
|
|
%item.surfaceNrm = %surfaceNrm;
|
|
}
|
|
else {
|
|
// Deploy through water
|
|
if (%searchResult.getType() & $TypeMasks::WaterObjectType) {
|
|
%item.surface = %surface;
|
|
%item.surfacePt = %surfacePt;
|
|
%item.surfaceNrm = %surfaceNrm;
|
|
}
|
|
// Redundant - already checking StaticShape above now (v0.62a)
|
|
// // Deploy on StaticShapes
|
|
// else if (%searchResult.getType() & $TypeMasks::StaticShapeObjectType) {
|
|
// %item.surface = %surface;
|
|
// %item.surfacePt = %surfacePt;
|
|
// %item.surfaceNrm = %surfaceNrm;
|
|
// }
|
|
// Don't set the item
|
|
// TODO - make a proper $NotDeployableReason for this
|
|
else
|
|
%disqualified = $NotDeployableReason::MaxDeployed;
|
|
}
|
|
}
|
|
if (!getTerrainAngle(%surfaceNrm) && %item.flatMaxDeployDis !$= "") {
|
|
$MaxDeployDistance = %item.flatMaxDeployDis;
|
|
$MinDeployDistance = %item.flatMinDeployDis;
|
|
}
|
|
}
|
|
|
|
%item.surfaceinher = 0;
|
|
if (%item.surface.needsFit == 1) {
|
|
%item.surfaceinher = 1;
|
|
// new code
|
|
%mask = invFace(%item.surfaceNrm);
|
|
%narrower = vectorMultiply(%mask,%item.surface.getRealSize());
|
|
%subject = vectorNormalize(topVec(%narrower));
|
|
%item.surfaceNrm2 = realVec(%item.surface,%subject);
|
|
// old code
|
|
// if (vAbs(%item.surfaceNrm) $= "0 0 1")
|
|
// %item.surfaceNrm2 = realVec(%item.surface,"1 0 0");
|
|
// else
|
|
// %item.surfaceNrm2 = realVec(%item.surface,"0 0 1");
|
|
%item.surfaceNrm = VectorNormalize(realVec(%item.surface,%surfaceNrm));
|
|
%item.surfaceNrm2 = VectorNormalize(%item.surfaceNrm2);
|
|
%mCenter = "0 0 -0.5";
|
|
%className = %item.surface.getDataBlock().className;
|
|
if (%className !$= "tree" && %className !$= "crate" && %className !$= "vpad")
|
|
%item.surfacePt = link(%item.surface,%surfaceNrm,%surfacePt,VectorScale(getjoint(%item),0.5),%mCenter);
|
|
if (%className $= "decoration") {
|
|
if (%item.surface.getDataBlock().getName() $= "DeployedDecoration6") {
|
|
%item.surfacePt = vectorAdd(%item.surfacePt,vectorScale(realVec(%item.surface,"0 0 1"),3.3));
|
|
%item.surfaceNrm = realVec(%item.surface,"0 0 1");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (%item.testMaxDeployed(%plyr))
|
|
{
|
|
%disqualified = $NotDeployableReason::MaxDeployed;
|
|
}
|
|
else if (%item.testNoSurfaceInRange(%plyr))
|
|
{
|
|
%disqualified = $NotDeployableReason::NoSurfaceFound;
|
|
}
|
|
else if (%item.testNoTerrainFound(%surface))
|
|
{
|
|
%disqualified = $NotDeployableReason::NoTerrainFound;
|
|
}
|
|
else if (%item.testNoInteriorFound())
|
|
{
|
|
%disqualified = $NotDeployableReason::NoInteriorFound;
|
|
}
|
|
else if (%item.testSurfaceTooNarrow(%surface))
|
|
{
|
|
%disqualified = $NotDeployableReason::SurfaceTooNarrow;
|
|
}
|
|
else if (%item.testSlopeTooGreat(%surface, %surfaceNrm))
|
|
{
|
|
%disqualified = $NotDeployableReason::SlopeTooGreat;
|
|
}
|
|
else if (%item.testSelfTooClose(%plyr, %surfacePt))
|
|
{
|
|
%disqualified = $NotDeployableReason::SelfTooClose;
|
|
}
|
|
else if (%item.testObjectTooClose(%surfacePt,%plyr))
|
|
{
|
|
%disqualified = $NotDeployableReason::ObjectTooClose;
|
|
}
|
|
else if (%item.testTurretTooClose(%plyr) && $Host::Purebuild != 1)
|
|
{
|
|
%disqualified = $NotDeployableReason::TurretTooClose;
|
|
}
|
|
else if (%item.testInventoryTooClose(%plyr))
|
|
{
|
|
%disqualified = $NotDeployableReason::InventoryTooClose;
|
|
}
|
|
else if (%item.testTurretSaturation() && $Host::Purebuild != 1)
|
|
{
|
|
%disqualified = $NotDeployableReason::TurretSaturation;
|
|
}
|
|
else if (%disqualified == $NotDeployableReason::None)
|
|
{
|
|
// Test that there are no obstructing objects that this object
|
|
// will intersect with
|
|
//
|
|
%rot = %item.getInitialRotation(%plyr);
|
|
if (%item.deployed.className $= "DeployedTurret")
|
|
{
|
|
%xform = %item.deployed.getDeployTransform(%item.surfacePt, %item.surfaceNrm);
|
|
}
|
|
else
|
|
{
|
|
%xform = %surfacePt SPC %rot;
|
|
}
|
|
}
|
|
|
|
if (%plyr.getMountedImage($BackpackSlot) == %item) //player still have the item?
|
|
{
|
|
if (%disqualified)
|
|
activateDeploySensorRed(%plyr);
|
|
else
|
|
activateDeploySensorGrn(%plyr);
|
|
|
|
if (%plyr.client.deployPack == true) {
|
|
%item.attemptDeploy(%plyr, %slot, %disqualified);
|
|
}
|
|
else
|
|
{
|
|
%plyr.deployCheckThread = %item.schedule(25, "testInvalidDeployConditions", %plyr, %slot); //update checks every 50 milliseconds
|
|
}
|
|
}
|
|
else
|
|
deactivateDeploySensor(%plyr);
|
|
}
|
|
|
|
function checkPositions(%pos1, %pos2)
|
|
{
|
|
%passed = true;
|
|
if ((mFloor(getWord(%pos1, 0)) - mFloor(getWord(%pos2,0))))
|
|
%passed = false;
|
|
if ((mFloor(getWord(%pos1, 1)) - mFloor(getWord(%pos2,1))))
|
|
%passed = false;
|
|
if ((mFloor(getWord(%pos1, 2)) - mFloor(getWord(%pos2,2))))
|
|
%passed = false;
|
|
return %passed;
|
|
}
|
|
|
|
function ShapeBaseImageData::attemptDeploy(%item, %plyr, %slot, %disqualified)
|
|
{
|
|
deactivateDeploySensor(%plyr);
|
|
Deployables::displayErrorMsg(%item, %plyr, %slot, %disqualified);
|
|
}
|
|
|
|
function activateDeploySensorRed(%pl)
|
|
{
|
|
if (%pl.deploySensor !$= "red")
|
|
{
|
|
messageClient(%pl.client, 'msgDeploySensorRed', "");
|
|
%pl.deploySensor = "red";
|
|
}
|
|
}
|
|
|
|
function activateDeploySensorGrn(%pl)
|
|
{
|
|
if (%pl.deploySensor !$= "green")
|
|
{
|
|
messageClient(%pl.client, 'msgDeploySensorGrn', "");
|
|
%pl.deploySensor = "green";
|
|
}
|
|
}
|
|
|
|
function deactivateDeploySensor(%pl)
|
|
{
|
|
if (%pl.deploySensor !$= "")
|
|
{
|
|
messageClient(%pl.client, 'msgDeploySensorOff', "");
|
|
%pl.deploySensor = "";
|
|
}
|
|
}
|
|
|
|
function Deployables::displayErrorMsg(%item, %plyr, %slot, %error)
|
|
{
|
|
deactivateDeploySensor(%plyr);
|
|
|
|
%errorSnd = '~wfx/misc/misc.error.wav';
|
|
switch (%error)
|
|
{
|
|
case $NotDeployableReason::None:
|
|
if (isObject(%plyr.client)) {
|
|
if (!spamCheck(%plyr.client)) {
|
|
%deplObj = %item.onDeploy(%plyr, %slot);
|
|
%deplObj.depTime = getSimTime();
|
|
// TODO - temporary - remove
|
|
if ($TimedDisCenter !$= "") {
|
|
if (vectorLen(vectorDist($TimedDisCenter,%deplObj.getPosition())) < 150 && %plyr.client != nameToID(LocalClientConnection))
|
|
%deplObj.timedDis = %deplObj.getDataBlock().schedule(1 * 5 * 1000,disassemble,0,%deplObj);
|
|
}
|
|
// ----
|
|
messageClient(%plyr.client, 'MsgTeamDeploySuccess', "");
|
|
return;
|
|
}
|
|
else if ($Host::Prison::DeploySpamRemoveRecentMS !$= "" && $Host::Prison::DeploySpamRemoveRecentMS > 0) {
|
|
%group = nameToID("MissionCleanup/Deployables");
|
|
%count = %group.getCount();
|
|
for(%i=0;%i<%count;%i++) {
|
|
%obj = %group.getObject(%i);
|
|
if (%obj.getOwner() == %plyr.client && getSimTime() - $Host::Prison::DeploySpamRemoveRecentMS < %obj.depTime) {
|
|
%obj.getDataBlock().schedule(50 * %disCount++,disassemble,%plyr,%obj);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
%item.onDeploy(%plyr, %slot);
|
|
messageClient(%plyr.client, 'MsgTeamDeploySuccess', "");
|
|
return;
|
|
}
|
|
case $NotDeployableReason::NoSurfaceFound:
|
|
%msg = '\c2Item must be placed within reach.%1';
|
|
|
|
case $NotDeployableReason::MaxDeployed:
|
|
%msg = '\c2Your team\'s control network has reached its capacity for this item.%1';
|
|
|
|
case $NotDeployableReason::SlopeTooGreat:
|
|
%msg = '\c2Surface is too steep to place this item on.%1';
|
|
|
|
case $NotDeployableReason::SelfTooClose:
|
|
%msg = '\c2You are too close to the surface you are trying to place the item on.%1';
|
|
|
|
case $NotDeployableReason::ObjectTooClose:
|
|
%msg = '\c2You cannot place this item so close to another object.%1';
|
|
|
|
case $NotDeployableReason::NoTerrainFound:
|
|
%msg = '\c2You must place this on outdoor terrain.%1';
|
|
|
|
case $NotDeployableReason::NoInteriorFound:
|
|
%msg = '\c2You must place this on a solid surface.%1';
|
|
|
|
case $NotDeployableReason::TurretTooClose:
|
|
%msg = '\c2Interference from a nearby turret prevents placement here.%1';
|
|
|
|
case $NotDeployableReason::TurretSaturation:
|
|
%msg = '\c2There are too many turrets nearby.%1';
|
|
|
|
case $NotDeployableReason::SurfaceTooNarrow:
|
|
%msg = '\c2There is not adequate surface to clamp to here.%1';
|
|
|
|
case $NotDeployableReason::InventoryTooClose:
|
|
%msg = '\c2Interference from a nearby inventory prevents placement here.%1';
|
|
|
|
default:
|
|
%msg = '\c2Deploy failed.';
|
|
}
|
|
messageClient(%plyr.client, 'MsgDeployFailed', %msg, %errorSnd);
|
|
}
|
|
|
|
function ShapeBaseImageData::onActivate(%data, %obj, %slot)
|
|
{
|
|
//Tinman - apparently, anything that uses the generic onActivate() method is a deployable.
|
|
//repair packs, cloak packs, shield, etc... all overload this method...
|
|
%data.testInvalidDeployConditions(%obj, %slot);
|
|
|
|
//whether the test passed or not, reset the image trigger (deployables don't have an on/off toggleable state)
|
|
%obj.setImageTrigger(%slot, false);
|
|
}
|
|
|
|
|
|
|
|
|
|
function ShapeBaseImageData::onDeploy(%item, %plyr, %slot)
|
|
{
|
|
if (%item.item $= "MotionSensorDeployable" || %item.item $= "PulseSensorDeployable")
|
|
{
|
|
%plyr.deploySensors--;
|
|
%plyr.client.updateSensorPackText(%plyr.deploySensors);
|
|
if (%plyr.deploySensors <= 0)
|
|
{
|
|
// take the deployable off the player's back and out of inventory
|
|
%plyr.unmountImage(%slot);
|
|
%plyr.decInventory(%item.item, 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// take the deployable off the player's back and out of inventory
|
|
%plyr.unmountImage(%slot);
|
|
%plyr.decInventory(%item.item, 1);
|
|
}
|
|
|
|
// create the actual deployable !!!!!!!!!!!!!!!!STOP AND LOOK AT ME!!!!!!!!!!!!!!!!! ???????WHY??????
|
|
%rot = %item.getInitialRotation(%plyr);
|
|
if (%item.deployed.className $= "DeployedTurret")
|
|
%className = "Turret";
|
|
else
|
|
%className = "StaticShape";
|
|
|
|
%deplObj = new (%className)() {
|
|
dataBlock = %item.deployed;
|
|
};
|
|
|
|
|
|
|
|
// set orientation
|
|
if (%className $= "Turret")
|
|
%deplObj.setDeployRotation(%item.surfacePt, %item.surfaceNrm);
|
|
else
|
|
%deplObj.setTransform(VectorAdd(%item.surfacePt, %plac) SPC %rot);
|
|
|
|
|
|
// set the recharge rate right away
|
|
if (%deplObj.getDatablock().rechargeRate)
|
|
%deplObj.setRechargeRate(%deplObj.getDatablock().rechargeRate);
|
|
|
|
// set team, owner, and handle
|
|
%deplObj.team = %plyr.client.Team;
|
|
%deplObj.setOwner(%plyr);
|
|
|
|
// set the sensor group if it needs one
|
|
if (%deplObj.getTarget() != -1)
|
|
setTargetSensorGroup(%deplObj.getTarget(), %plyr.client.team);
|
|
|
|
// place the deployable in the MissionCleanup/Deployables group (AI reasons)
|
|
addToDeployGroup(%deplObj);
|
|
|
|
//let the AI know as well...
|
|
AIDeployObject(%plyr.client, %deplObj);
|
|
|
|
// play the deploy sound
|
|
serverPlay3D(%item.deploySound, %deplObj.getTransform());
|
|
|
|
// increment the team count for this deployed object
|
|
|
|
$TeamDeployedCount[%plyr.team, %item.item]++;
|
|
|
|
if (%classname !$= "Item")
|
|
%deplObj.deploy();
|
|
|
|
addDSurface(%item.surface,%deplObj);
|
|
return %deplObj;
|
|
}
|
|
|
|
function ShapeBaseImageData::getInitialRotation(%item, %plyr)
|
|
{
|
|
return rotFromTransform(%plyr.getTransform());
|
|
}
|
|
|
|
function MotionSensorDeployableImage::getInitialRotation(%item, %plyr)
|
|
{
|
|
%rotAxis = vectorNormalize(vectorCross(%item.surfaceNrm, "0 0 1"));
|
|
if (getWord(%item.surfaceNrm, 2) == 1 || getWord(%item.surfaceNrm, 2) == -1)
|
|
%rotAxis = vectorNormalize(vectorCross(%item.surfaceNrm, "0 1 0"));
|
|
return %rotAxis SPC mACos(vectorDot(%item.surfaceNrm, "0 0 1"));
|
|
}
|
|
|
|
function MotionSensorDeployable::onPickup(%this, %pack, %player, %amount)
|
|
{
|
|
// %this = Sensor pack datablock
|
|
// %pack = Sensor pack object number
|
|
// %player = player
|
|
// %amount = amount picked up (1)
|
|
|
|
if (%pack.sensors $= "")
|
|
{
|
|
// assume that this is a pack that has been placed in a mission
|
|
// this case was handled in ::onInventory below (max sensors);
|
|
}
|
|
else
|
|
{
|
|
// find out how many sensor were in the pack
|
|
%player.deploySensors = %pack.sensors;
|
|
%player.client.updateSensorPackText(%player.deploySensors);
|
|
}
|
|
}
|
|
|
|
function MotionSensorDeployable::onThrow(%this,%pack,%player)
|
|
{
|
|
// %this = Sensor pack datablock
|
|
// %pack = Sensor pack object number
|
|
// %player = player
|
|
|
|
%player.throwSensorPack = 1;
|
|
%pack.sensors = %player.deploySensors;
|
|
%player.deploySensors = 0;
|
|
%player.client.updateSensorPackText(%player.deploySensors);
|
|
// do the normal ItemData::onThrow stuff -- sound and schedule deletion
|
|
serverPlay3D(ItemThrowSound, %player.getTransform());
|
|
%pack.schedulePop();
|
|
}
|
|
|
|
function MotionSensorDeployable::onInventory(%this,%player,%value)
|
|
{
|
|
// %this = Sensor pack datablock
|
|
// %player = player
|
|
// %value = 1 if gaining a pack, 0 if losing a pack
|
|
|
|
if (%player.getClassName() $= "Player")
|
|
{
|
|
if (%value)
|
|
{
|
|
// player picked up or bought a motion sensor pack
|
|
%player.deploySensors = %this.maxSensors;
|
|
%player.client.updateSensorPackText(%player.deploySensors);
|
|
}
|
|
else
|
|
{
|
|
// player dropped or sold a motion sensor pack
|
|
if (%player.throwSensorPack)
|
|
{
|
|
// player threw the pack
|
|
%player.throwSensorPack = 0;
|
|
// everything handled in ::onThrow above
|
|
}
|
|
else
|
|
{
|
|
//the pack was sold at an inventory station, or unmounted because the player
|
|
// used all the sensors
|
|
%player.deploySensors = 0;
|
|
%player.client.updateSensorPackText(%player.deploySensors);
|
|
}
|
|
}
|
|
}
|
|
Pack::onInventory(%this,%player,%value);
|
|
}
|
|
|
|
function PulseSensorDeployable::onPickup(%this, %pack, %player, %amount)
|
|
{
|
|
// %this = Sensor pack datablock
|
|
// %pack = Sensor pack object number
|
|
// %player = player
|
|
// %amount = amount picked up (1)
|
|
|
|
if (%pack.sensors $= "")
|
|
{
|
|
// assume that this is a pack that has been placed in a mission
|
|
// this case was handled in ::onInventory below (max sensors);
|
|
}
|
|
else
|
|
{
|
|
// find out how many sensor were in the pack
|
|
%player.deploySensors = %pack.sensors;
|
|
%player.client.updateSensorPackText(%player.deploySensors);
|
|
}
|
|
}
|
|
|
|
function PulseSensorDeployable::onThrow(%this,%pack,%player)
|
|
{
|
|
// %this = Sensor pack datablock
|
|
// %pack = Sensor pack object number
|
|
// %player = player
|
|
|
|
%player.throwSensorPack = 1;
|
|
%pack.sensors = %player.deploySensors;
|
|
%player.deploySensors = 0;
|
|
%player.client.updateSensorPackText(%player.deploySensors);
|
|
// do the normal ItemData::onThrow stuff -- sound and schedule deletion
|
|
serverPlay3D(ItemThrowSound, %player.getTransform());
|
|
%pack.schedulePop();
|
|
}
|
|
|
|
function PulseSensorDeployable::onInventory(%this,%player,%value)
|
|
{
|
|
// %this = Sensor pack datablock
|
|
// %player = player
|
|
// %value = 1 if gaining a pack, 0 if losing a pack
|
|
|
|
if (%player.getClassName() $= "Player")
|
|
{
|
|
if (%value)
|
|
{
|
|
// player picked up or bought a motion sensor pack
|
|
%player.deploySensors = %this.maxSensors;
|
|
%player.client.updateSensorPackText(%player.deploySensors);
|
|
}
|
|
else
|
|
{
|
|
// player dropped or sold a motion sensor pack
|
|
if (%player.throwSensorPack)
|
|
{
|
|
// player threw the pack
|
|
%player.throwSensorPack = 0;
|
|
// everything handled in ::onThrow above
|
|
}
|
|
else
|
|
{
|
|
//the pack was sold at an inventory station, or unmounted because the player
|
|
// used all the sensors
|
|
%player.deploySensors = 0;
|
|
%player.client.updateSensorPackText(%player.deploySensors);
|
|
}
|
|
}
|
|
}
|
|
Pack::onInventory(%this,%player,%value);
|
|
}
|
|
|
|
function TurretIndoorDeployableImage::getInitialRotation(%item, %plyr)
|
|
{
|
|
%surfaceAngle = getTerrainAngle(%item.surfaceNrm);
|
|
if (%surfaceAngle > 155)
|
|
%item.deployed = TurretDeployedCeilingIndoor;
|
|
else if (%surfaceAngle > 45)
|
|
%item.deployed = TurretDeployedWallIndoor;
|
|
else
|
|
%item.deployed = TurretDeployedFloorIndoor;
|
|
}
|
|
|
|
function TurretIndoorDeployable::onPickup(%this, %obj, %shape, %amount)
|
|
{
|
|
// created to prevent console errors
|
|
}
|
|
|
|
function TurretOutdoorDeployable::onPickup(%this, %obj, %shape, %amount)
|
|
{
|
|
// created to prevent console errors
|
|
}
|
|
|
|
function InventoryDeployable::onPickup(%this, %obj, %shape, %amount)
|
|
{
|
|
// created to prevent console errors
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// deployed station functions
|
|
function DeployedStationInventory::onEndSequence(%data, %obj, %thread)
|
|
{
|
|
Parent::onEndSequence(%data, %obj, %thread);
|
|
if (%thread == $DeployThread)
|
|
{
|
|
%trigger = new Trigger()
|
|
{
|
|
dataBlock = stationTrigger;
|
|
polyhedron = "-0.125 0.0 0.1 0.25 0.0 0.0 0.0 -0.7 0.0 0.0 0.0 1.0";
|
|
};
|
|
MissionCleanup.add(%trigger);
|
|
|
|
%trans = %obj.getTransform();
|
|
%vSPos = getWords(%trans,0,2);
|
|
%vRot = getWords(%trans,3,5);
|
|
%vAngle = getWord(%trans,6);
|
|
%matrix = VectorOrthoBasis(%vRot @ " " @ %vAngle + 0.0);
|
|
%yRot = getWords(%matrix, 3, 5);
|
|
%pos = vectorAdd(%vSPos, vectorScale(%yRot, -0.1));
|
|
|
|
%trigger.setTransform(%pos @ " " @ %vRot @ " " @ %vAngle);
|
|
|
|
// associate the trigger with the station
|
|
%trigger.station = %obj;
|
|
%trigger.mainObj = %obj;
|
|
%trigger.disableObj = %obj;
|
|
%obj.trigger = %trigger;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//DeployedMotionSensor:
|
|
//--------------------------------------------------------------------------
|
|
|
|
function DeployedMotionSensor::onDestroyed(%this, %obj, %prevState)
|
|
{
|
|
if (%obj.isRemoved)
|
|
return;
|
|
%obj.isRemoved = true;
|
|
//%obj.hide(true);
|
|
Parent::onDestroyed(%this, %obj, %prevState);
|
|
$TeamDeployedCount[%obj.team, MotionSensorDeployable]--;
|
|
remDSurface(%obj);
|
|
%obj.schedule(500, "delete");
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//DeployedPulseSensor:
|
|
//--------------------------------------------------------------------------
|
|
function PulseSensorDeployableImage::onActivate(%data, %obj, %slot)
|
|
{
|
|
Parent::onActivate( %data, %obj, %slot );
|
|
//%data.testInvalidDeployConditions(%obj, %slot);
|
|
}
|
|
|
|
function DeployedPulseSensor::onDestroyed(%this, %obj, %prevState)
|
|
{
|
|
if (%obj.isRemoved)
|
|
return;
|
|
%obj.isRemoved = true;
|
|
Parent::onDestroyed(%this, %obj, %prevState);
|
|
$TeamDeployedCount[%obj.team, PulseSensorDeployable]--;
|
|
remDSurface(%obj);
|
|
%obj.schedule(300, "delete");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// deployed turret functions
|
|
|
|
function DeployedTurret::onAdd(%data, %obj)
|
|
{
|
|
Parent::onAdd(%data, %obj);
|
|
// auto-mount the barrel
|
|
%obj.mountImage(%data.barrel, 0, false);
|
|
}
|
|
|
|
function DeployedTurret::onDestroyed(%this, %obj, %prevState) {
|
|
if (%obj.isRemoved)
|
|
return;
|
|
if ($Host::InvincibleDeployables != 1 || %obj.damageFailedDecon || $DestroyableTurrets == 1) {
|
|
%obj.isRemoved = true;
|
|
%turType = %this.getName();
|
|
// either it'll be an outdoor turret, or one of the three types of indoor turret
|
|
// (floor, ceiling, wall)
|
|
if (%turType $= "TurretDeployedOutdoor")
|
|
%turType = "TurretOutdoorDeployable";
|
|
else if (%turType $= "TurretDeployedBase")
|
|
%turType = "TurretBasePack";
|
|
else
|
|
%turType = "TurretIndoorDeployable";
|
|
// decrement team count
|
|
$TeamDeployedCount[%obj.team, %turType]--;
|
|
remDSurface(%obj);
|
|
%obj.schedule(700, "delete");
|
|
}
|
|
Parent::onDestroyed(%this, %obj, %prevState);
|
|
}
|
|
|
|
function countTurretsAllowed(%type)
|
|
{
|
|
for(%j = 1; %j < Game.numTeams; %j++)
|
|
%teamPlayerCount[%j] = 0;
|
|
%numClients = ClientGroup.getCount();
|
|
for(%i = 0; %i < %numClients; %i++)
|
|
{
|
|
%cl = ClientGroup.getObject(%i);
|
|
if (%cl.team > 0)
|
|
%teamPlayerCount[%cl.team]++;
|
|
}
|
|
// the bigger team determines the number of turrets allowed
|
|
%maxPlayers = %teamPlayerCount[1] > %teamPlayerCount[2] ? %teamPlayerCount[1] : %teamPlayerCount[2];
|
|
// each team can have 1 turret of each type (indoor/outdoor) for every 2 players
|
|
// minimum and maximums are defined in deployables.cs
|
|
%teamTurretMax = mFloor(%maxPlayers / 2);
|
|
if (%teamTurretMax < $TeamDeployableMin[%type])
|
|
%teamTurretMax = $TeamDeployableMin[%type];
|
|
else if (%teamTurretMax > $TeamDeployableMax[%type])
|
|
%teamTurretMax = $TeamDeployableMax[%type];
|
|
|
|
return %teamTurretMax;
|
|
}
|
|
|
|
function spamCheck(%cl) {
|
|
if ($Host::Prison::Enabled != true || $Host::Prison::DeploySpam != true || %cl.isAdmin || %cl.isSuperAdmin)
|
|
return false;
|
|
%simTime = getSimTime();
|
|
if (%simTime - %cl.lastDeployTime > $Host::Prison::DeploySpamResetWarnCountTime * 1000)
|
|
%cl.spamCount = 0; // Reset spam count
|
|
if (%simTime - %cl.lastDeployTime < $Host::Prison::DeploySpamCheckTimeMS) {
|
|
%cl.spamCount++;
|
|
if (%cl.spamCount > $Host::Prison::DeploySpamWarnings) {
|
|
%cl.spamPunishCount++;
|
|
%cl.spamCount = 0;
|
|
%cl.lastDeployTime = 0;
|
|
%punishTime = $Host::Prison::DeploySpamTime;
|
|
%kills = 3;
|
|
if (%cl.spamPunishCount > %kills) {
|
|
if ($Host::Prison::DeploySpamMultiply > 0) {
|
|
%punishTime = (%cl.spamPunishCount - %kills) * $Host::Prison::DeploySpamTime;
|
|
if (%punishTime > $Host::Prison::DeploySpamMaxTime)
|
|
%punishTime = $Host::Prison::DeploySpamMaxTime;
|
|
}
|
|
// TODO - should really use some better formatting method...
|
|
if (%punishTime > 0) {
|
|
if (%punishTime >= 60) {
|
|
if (%punishTime > 60) {
|
|
%minutes = mFloor(%punishTime / 60);
|
|
messageClient(%cl,'msgClient','\c2You will do %1 minutes in jail for spamming deployables.',%minutes);
|
|
messageAllExcept(%cl,-1,'msgClient','\c2%1 will do %2 minutes in jail for spamming deployables.',%cl.name,%minutes);
|
|
}
|
|
else {
|
|
messageClient(%cl,'msgClient','\c2You will do 1 minute in jail for spamming deployables.');
|
|
messageAllExcept(%cl,-1,'msgClient','\c2%1 will do 1 minute in jail for spamming deployables.',%cl.name);
|
|
}
|
|
}
|
|
else {
|
|
messageClient(%cl,'msgClient','\c2You will do %1 seconds in jail spamming.',%punishTime);
|
|
messageAllExcept(%cl,-1,'msgClient','\c2%1 will do %2 seconds in jail for spamming deployables.',%cl.name,%punishTime);
|
|
}
|
|
}
|
|
else {
|
|
messageClient(%cl,'msgClient','\c2You were put in jail for spamming deployables.');
|
|
messageAllExcept(%cl,-1,'msgClient','\c2%1 was put in jail for spamming deployables.',%cl.name);
|
|
}
|
|
jailPlayer(%cl,false,%punishTime);
|
|
}
|
|
else {
|
|
%cl.player.scriptKill(99);
|
|
messageClient(%cl,'msgClient','\c2You were killed for spamming deployables.');
|
|
messageAllExcept(%cl,-1,'msgClient','\c2%1 was killed for spamming deployables.',%cl.name);
|
|
}
|
|
return true;
|
|
}
|
|
// Warn player only if they've used up over half their warnings, to prevent message hud spam
|
|
else if (%cl.spamCount > mFloor(($Host::Prison::DeploySpamWarnings + 1) / 2)) {
|
|
centerPrint(%cl,"Do not spam, or face the consequences",2,1);
|
|
messageClient(%cl,'msgClient',"~wfx/misc/misc.error.wav");
|
|
return true;
|
|
}
|
|
}
|
|
%cl.lastDeployTime = %simTime;
|
|
return false;
|
|
}
|
|
|
|
//------------------------------
|
|
// Deployable extra explosions
|
|
//------------------------------
|
|
|
|
datablock GrenadeProjectileData(DeployableFireball) {
|
|
projectileShapeName = "weapon_chaingun_ammocasing.dts";
|
|
emitterDelay = -1;
|
|
directDamage = 0.0;
|
|
hasDamageRadius = true;
|
|
indirectDamage = 0.10;
|
|
damageRadius = 10.0;
|
|
radiusDamageType = $DamageType::Debris;
|
|
kickBackStrength = 1000;
|
|
bubbleEmitTime = 1.0;
|
|
|
|
explosion = "PlasmaBoltExplosion";
|
|
splash = PlasmaSplash;
|
|
explodeOnMaxBounce = true;
|
|
|
|
velInheritFactor = 0.5;
|
|
|
|
baseEmitter = DebrisFireEmitter;
|
|
smokeEmitter = DebrisSmokeEmitter;
|
|
|
|
grenadeElasticity = 0.4;
|
|
grenadeFriction = 0.2;
|
|
armingDelayMS = 400;
|
|
muzzleVelocity = 20.00;
|
|
drag = 0.1;
|
|
|
|
hasLight = true;
|
|
lightRadius = 3.0;
|
|
lightColor = "1 0.75 0.25";
|
|
};
|
|
|
|
datablock StaticShapeData(DeployedLTarget) : StaticShapeDamageProfile {
|
|
className = "decontarget";
|
|
shapeFile = "xmiscf.dts";
|
|
|
|
maxDamage = 0.5;
|
|
destroyedLevel = 0.5;
|
|
disabledLevel = 0.3;
|
|
|
|
explosion = HandGrenadeExplosion;
|
|
expDmgRadius = 1.0;
|
|
expDamage = 0.05;
|
|
expImpulse = 200;
|
|
|
|
dynamicType = $TypeMasks::StaticShapeObjectType;
|
|
deployedObject = true;
|
|
cmdCategory = "DSupport";
|
|
cmdIcon = CMDSensorIcon;
|
|
cmdMiniIconName = "commander/MiniIcons/com_deploymotionsensor";
|
|
targetNameTag = 'Deployed DeconTarget';
|
|
deployAmbientThread = true;
|
|
debrisShapeName = "debris_generic_small.dts";
|
|
debris = DeployableDebris;
|
|
heatSignature = 0;
|
|
};
|
|
|
|
function DeployedLTarget::onDestroyed(%this,%obj,%prevState) {
|
|
if (%obj.isRemoved)
|
|
return;
|
|
%obj.isRemoved = true;
|
|
Parent::onDestroyed(%this,%obj,%prevState);
|
|
remDSurface(%obj);
|
|
%obj.schedule(500, "delete");
|
|
if (isObject(%obj.lMain)) {
|
|
%obj.lMain.setDamageState(Destroyed);
|
|
}
|
|
}
|
|
|
|
function fireBallExplode(%obj,%numFb) {
|
|
|
|
%source = %obj;
|
|
for (%i=0;%i<%numFb;%i++) {
|
|
%x = (getRandom() * 0.4) - 0.2;
|
|
%y = (getRandom() * 0.4) - 0.2;
|
|
%z = getRandom() / 2;
|
|
%vec = %x SPC %y SPC %z;
|
|
%pos = vectorAdd(posFromTransform(%obj.getTransform()),vectorScale(%vec,3));
|
|
%p = new (GrenadeProjectile)() {
|
|
dataBlock = DeployableFireball;
|
|
initialDirection = %vec;
|
|
initialPosition = %pos;
|
|
sourceObject = %source;
|
|
sourceSlot = 1;
|
|
vehicleObject = %obj;
|
|
};
|
|
MissionCleanup.add(%p);
|
|
}
|
|
}
|
|
|
|
function cascade(%obj,%cascade) {
|
|
if (%obj.cascade)
|
|
%cascade = true;
|
|
if ($Host::Cascade == false && !%cascade)
|
|
return;
|
|
%list = %obj.dObj;
|
|
%count = getWordCount(%list);
|
|
for(%i=0;%i<%count;%i++) {
|
|
%obj2 = getWord(%list,%i);
|
|
if ($Host::Cascade == false) {
|
|
%obj2.cascade = true;
|
|
%random = getRandom() * 1000;
|
|
%obj2.getDataBlock().schedule(%random,disassemble,0,%obj2);
|
|
}
|
|
else {
|
|
%random = getRandom() * 1000;
|
|
%obj2.schedule(%random,setDamageState,Destroyed);
|
|
}
|
|
}
|
|
%obj.cascaded = true;
|
|
}
|
|
|
|
// TODO - handle dup disassemblies? only allow every n seconds?
|
|
|
|
function disassemble(%data,%plyr,%obj) {
|
|
if (!isObject(%obj))
|
|
return;
|
|
if (%obj.lMain) {
|
|
if (isObject(%obj.lMain)) {
|
|
%obj.lMain.getDataBlock().disassemble(%plyr,%obj.lMain);
|
|
return;
|
|
}
|
|
else {
|
|
serverPlay3D(DSound,%obj.getTransform());
|
|
%obj.schedule(500,"delete");
|
|
remDSurface(%obj);
|
|
return;
|
|
}
|
|
}
|
|
else if (isObject(%obj.lTarget)) {
|
|
%obj.lTarget.startFade(250,0,1);
|
|
%obj.lTarget.schedule(500,"delete");
|
|
}
|
|
%obj.isRemoved = 1;
|
|
serverPlay3D(DSound,%obj.getTransform());
|
|
if (%obj.getType() & $TypeMasks::StaticShapeObjectType
|
|
|| %obj.getType() & $TypeMasks::ItemObjectType)
|
|
%obj.startFade(500,0,1);
|
|
if (isObject(%obj.trigger))
|
|
%obj.trigger.delete();
|
|
if (isObject(%obj.emitter))
|
|
%obj.emitter.delete();
|
|
%obj.schedule(500,"delete");
|
|
%revItem = %obj.getDataBlock().getName();
|
|
%newPack = $ReverseDeployItem[%revItem];
|
|
if (getWord(%newPack,0) $= "poof")
|
|
$TeamDeployedCount[%obj.team,getWord(%newPack,1)]--;
|
|
else
|
|
$TeamDeployedCount[%obj.team,%newPack]--;
|
|
cascade(%obj,false);
|
|
remDSurface(%obj);
|
|
}
|
|
|
|
function StaticShapeData::disassemble(%data,%plyr,%obj) {
|
|
if (!isObject(%obj))
|
|
return;
|
|
if (%obj.getDataBlock().classname $= "Generator") {
|
|
%obj.getDataBlock().losePower(%obj);
|
|
%loc = findWord($PowerList,%obj);
|
|
if (%loc !$= "")
|
|
$PowerList = listDel($PowerList,%loc);
|
|
%obj.isRemoved = true;
|
|
}
|
|
disassemble(%data,%plyr,%obj);
|
|
}
|
|
|
|
function expertModeOn() {
|
|
exec("scripts/expertLibraries.cs");
|
|
$Host::ExpertMode = 1;
|
|
}
|
|
|
|
function expertModeOff() {
|
|
exec("scripts/libraries.cs");
|
|
$Host::ExpertMode = 0;
|
|
|
|
// Bring pack settings down from orbit
|
|
%count = ClientGroup.getCount();
|
|
for (%i=0;%i<%count;%i++) {
|
|
%client = ClientGroup.getObject(%i);
|
|
%player = %client.player;
|
|
if (isObject(%player)) {
|
|
%player.packSet = 0;
|
|
%player.expertSet = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
function delUndergroundDeployables(%quiet) {
|
|
%randomTime = 10000;
|
|
%group = nameToID("MissionCleanup/Deployables");
|
|
%count = %group.getCount();
|
|
for(%i=0;%i<%count;%i++) {
|
|
%obj = %group.getObject(%i);
|
|
if (%obj) {
|
|
%terrain = getTerrainHeight2(%obj.getPosition(),0,%obj);
|
|
if (getWord(vectorAdd(%obj.getPosition(),"0 0 0.25"),2) < getWord(%terrain,2) || %terrain $= "") {
|
|
warn("Deleting: " @ %obj @ " Name: " @ %obj.getDataBlock().getName());
|
|
%random = getRandom() * %randomTime;
|
|
%obj.getDataBlock().schedule(%random,"disassemble",%plyr, %obj); // Run Item Specific code.
|
|
%deleted++;
|
|
}
|
|
else
|
|
%checked++;
|
|
|
|
}
|
|
}
|
|
if (!%quiet) {
|
|
warn("Checked pieces: " @ %checked);
|
|
warn("Deleted pieces: " @ %deleted);
|
|
}
|
|
return %randomTime;
|
|
}
|
|
|
|
function delOrphanedPieces(%quiet) {
|
|
%randomTime = 10000;
|
|
%group = nameToID("MissionCleanup/Deployables");
|
|
%count = %group.getCount();
|
|
for(%i=0;%i<%count;%i++) {
|
|
%obj = %group.getObject(%i);
|
|
if (!isObject(%obj.getOwner())) {
|
|
if (!%quiet)
|
|
warn("Deleting: " @ %obj @ " Name: " @ %obj.getDataBlock().getName());
|
|
%random = getRandom() * %randomTime;
|
|
%obj.getDataBlock().schedule(%random,"disassemble",%plyr,%obj); // Run Item Specific code.
|
|
%deleted++;
|
|
}
|
|
else
|
|
%checked++;
|
|
}
|
|
if (!%quiet) {
|
|
warn("Checked pieces: " @ %checked);
|
|
warn("Deleted pieces: " @ %deleted);
|
|
}
|
|
return %randomTime;
|
|
}
|
|
|
|
function addDSurface(%surface,%obj) {
|
|
%surface = firstWord(%surface);
|
|
%list = %surface.dObj;
|
|
%obj.dSurface = firstWord(%surface);
|
|
%list = listAdd(%list,%obj,-1);
|
|
// warn("Added obj " @ %obj @ " to surface " @ %surface);
|
|
|
|
// For debugging
|
|
// %count = getWordCount(%list);
|
|
// for(%i=0;%i<%count;%i++) {
|
|
// %obj2 = getWord(%list,%i);
|
|
// if (!isObject(%obj2)) {
|
|
// error("surface: " @ %surface @ " - obj does not exist: " @ %obj2);
|
|
// %badIDs = %badIDs SPC %i;
|
|
// }
|
|
// }
|
|
// %list = listDel(%list,trim(%badIDs));
|
|
//warn(%surface @ " - " @ %list);
|
|
%surface.dObj = %list;
|
|
}
|
|
|
|
// TODO - verify
|
|
function remDSurface(%obj) {
|
|
%surface = %obj.dSurface;
|
|
if (isObject(%surface)) {
|
|
%list = %surface.dObj;
|
|
%loc = findWord(%list,%obj);
|
|
if (%loc !$= "") {
|
|
%list = listDel(%list,%loc);
|
|
// warn("Removed obj " @ %obj @ " from surface " @ %surface);
|
|
}
|
|
}
|
|
%surface.dObj = %list;
|
|
|
|
%list = %obj.dObj;
|
|
%count = getWordCount(%list);
|
|
for(%i=0;%i<%count;%i++) {
|
|
%obj2 = getWord(%list,%i);
|
|
if (isObject(%obj2)) {
|
|
%obj2.dSurface = "";
|
|
// warn("Removed surface " @ %obj @ " from obj " @ %obj2);
|
|
}
|
|
}
|
|
}
|
|
|
|
function GameBase::setOwner(%obj,%plyr,%client,%guid) {
|
|
if (!%client)
|
|
%client = %plyr.client;
|
|
if (!%guid)
|
|
%guid = %client.guid;
|
|
%obj.owner = %client;
|
|
%obj.ownerGUID = %guid;
|
|
}
|
|
|
|
function GameBase::getOwner(%obj) {
|
|
if (isObject(%obj.owner))
|
|
return %obj.owner;
|
|
%guid = %obj.ownerGUID;
|
|
if (!%guid)
|
|
%guid = %obj.lTarget.ownerGUID;
|
|
if (!%guid)
|
|
%guid = %obj.lMain.ownerGUID;
|
|
if (%guid) {
|
|
%count = ClientGroup.getCount();
|
|
for (%i=0;%i<%count;%i++) {
|
|
%client = ClientGroup.getObject(%i);
|
|
if (%client.guid == %guid)
|
|
return %client;
|
|
}
|
|
}
|
|
return "";
|
|
}
|