mirror of
https://github.com/Ragora/TribesReplay.git
synced 2026-01-19 17:44:45 +00:00
- (bug fix) Fixed an authentication hole that allowed arbitrary IP connections to a LAN server. The policy now is: LAN servers will disallow any connections from IP addresses that do not match the Class B network address of the server (or match one of them, in a multihomed server). So if your server's address is 12.13.14.15, clients from 12.13.*.* will be considered, but clients from 12.12.*.* will be immediately rejected. In addition, a LAN server will only allow 4 unique Class C ids at any one time. This should be sufficiently lenient for even the largest LAN parties, but should eliminate the auth hole. - (bug fix) Fixed a server crash on mission change when the last human player leaves the game in mid cycle. - (bug fix) Fixed a bug that could reset your Shape Detail setting to max - (bug fix) Client join message name correction - (bug fix) All known in-game Chat HUD bugs are fixed (partial lines from paging up/down and resize issues, etc.). - (bug fix) Infinite missile lock-on sound bug is fixed. Dead. Finito. No more. Pushing up the daisies. - (bug fix) Stitched up a hole associated with one of the base shapes. Small fry compared to the memory leaks. - (bug fix) Found a particle crash issue and plugged it up good. - (bug fix) Fixed a shield impact internal compile error that was crunching frame rate. - (bug fix) Turns out we tweaked it so inventory stations were counting as turrets for turret placement purposes. D'oh. Fixed. - (bug fix) A rare crash that occurred with the Radeon VE card has been resolved. - (bug fix) Fixed a crash that could occur when a flare grenade was released when inside a force field. - (bug fix) Deployable turrets (spider and spike) and Deployable inv stations now do damage in their explosion when they are destroyed. - (optimization) The following missions were refined in order to optimize framerate: Alcatraz Caldera Flashpoint Gauntlet IceBound Insalubria Overreach Respite Sirocco - (optimization) Adjusted the LOD of the logo projectors found in CnH missions. - (optimization) Changed object shield shapes from the form-fitting forcefields into a less poly-intensive dome effect. Also gave shields a lower memory profile. - (optimization) Changed the way the clouds' planes are clipped. Sky's the limit, right? - (optimization) Missile sound script calls moved from script into code for faster processing. - (memory leak) Fixed a large memory leak. This plus the other leaks mentioned here should finally put the nail in the coffin on the "degrading server performance" issue. - (memory leak) Fixed a memory leak associated with the pretty lightning effects on maps like Casern Cavite.memory leaks: - (memory leak) Fixed a memory leak in our fancy text list control and the gui text list. - (memory leak) Fixed a memory leak involving memory use and resource allocation. - (improvement) Targeting laser prediction should be better now. - (improvement) You can specify a server's IP address manually at the join screen - (improvement) You can now specify "-password <pw>" on the command line to join a server that requires a password. - (improvement) Heavy armors are tougher against snipers. You now require four headshots or five body shots to kill a Juggernaut with a laser rifle. - (improvement) Footspeed of all armors increased slightly, as well as a minor boost to jetpack performance. Some improvements made to air resistance for mediums and heavy armors (very subtle). - (improvement) The jetpack effect was reverted back to the old effect (by popular demand). - (improvement) A Chat HUD message has been added that is displayed whenever you try to deploy a mine, but your team's maximum number of mines has already been deployed. Previously, the mine would just blow up and not explain why it detonated. Now, it still blows up, but tells you why it happened. - (improvement) Polished up the health meter on the HUD so when you're still alive, it displays a visible sliver of positive health. - (improvement) Made framerate and gameplay changes to Caldera. The attackers' base has been moved farther from the defenders, and the switch has been put in one of the upper chambers, while the stations are located separately from the generators. The changes should fix a serious defensive advantage. - (improvement) After you buy a vehicle, you now fade into the driver's seat if your armor and pack make you an eligible pilot/driver. - (improvement) Added a "rogue" mine message so that if you are killed by a mine laid by someone who has left the building, the death message is more accurate. - (improvement) Increased speed of belly turret projectiles so that it is more effective in general (especially for air defense). - (improvement) Modified name tags of vehicles when you place your reticle over them. Names are now more consistent and descriptive. - (improvement) Missile and AA turrets now have a longer maximum range (you'll still need to deploy sensors to get this added range, but they can fire farther if you do). They also react more quickly to available targets. - (community) The "compose email", "forum post", and "news submission" windows are now resizable and movable.
893 lines
27 KiB
C#
893 lines
27 KiB
C#
//-------------------------------------- Ammo functions
|
|
function Ammo::onCollision(%data, %obj, %col)
|
|
{
|
|
// %data = datablock of object; %obj = object number
|
|
// %col = thing that collided with object (hopefully a player)
|
|
|
|
if (%col.getDataBlock().className $= Armor)
|
|
{
|
|
%ammoName = %data.getName();
|
|
%ammoStore = %col.inv[%ammoName];
|
|
|
|
// if player has ammo pack, increase max amount of ammo
|
|
if(%col.getMountedImage($BackpackSlot) != 0)
|
|
{
|
|
if(%col.getMountedImage($BackpackSlot).getName() $= "AmmoPackImage")
|
|
%aMax = (%col.getDataBlock().max[%ammoName]) + AmmoPack.max[%ammoName];
|
|
else
|
|
%aMax = %col.getDataBlock().max[%ammoName];
|
|
}
|
|
else
|
|
%aMax = %col.getDataBlock().max[%ammoName];
|
|
|
|
if(%col.inv[%ammoName] < %aMax)
|
|
{
|
|
%col.incInventory(%ammoName, $AmmoIncrement[%ammoName]);
|
|
serverPlay3D(ItemPickupSound, %col.getTransform());
|
|
%obj.respawn();
|
|
if (%col.client > 0)
|
|
messageClient(%col.client, 'MsgItemPickup', '\c0You picked up %1.', %data.pickUpName);
|
|
}
|
|
}
|
|
}
|
|
|
|
function GrenadeThrown::onCollision(%data, %obj, %col)
|
|
{
|
|
// nothing you can do now...
|
|
}
|
|
|
|
function HandInventory::onCollision(%data, %obj, %col)
|
|
{
|
|
// %data = datablock of object; %obj = object number
|
|
// %col = thing that collided with object (hopefully a player)
|
|
if (%col.getDataBlock().className $= Armor)
|
|
{
|
|
%ammoName = %data.getName();
|
|
%ammoStore = %col.inv[%ammoName];
|
|
|
|
// if player has ammo pack, increase max amount of ammo
|
|
if(%col.getMountedImage($BackpackSlot) != 0)
|
|
{
|
|
if(%col.getMountedImage($BackpackSlot).getName() $= "AmmoPackImage")
|
|
%aMax = (%col.getDataBlock().max[%ammoName]) + AmmoPack.max[%ammoName];
|
|
else
|
|
%aMax = %col.getDataBlock().max[%ammoName];
|
|
}
|
|
else
|
|
%aMax = %col.getDataBlock().max[%ammoName];
|
|
|
|
if(%data.isGrenade)
|
|
{
|
|
// it's a grenade -- see if it matches the type the player is carrying
|
|
%pgType = "None";
|
|
for(%x = 0; $InvGrenade[%x] !$= ""; %x++)
|
|
{
|
|
%gren = $NameToInv[$InvGrenade[%x]];
|
|
if(%col.inv[%gren] > 0)
|
|
{
|
|
%pgType = %gren;
|
|
break;
|
|
}
|
|
}
|
|
if((%pgType $= "None") || (%pgType $= %ammoName))
|
|
{
|
|
// player either has no grenades or this type of grenades -- OK to pick up more
|
|
%canPickup = true;
|
|
}
|
|
else
|
|
{
|
|
// player has a different kind of grenade -- don't pick this kind up
|
|
%canPickup = false;
|
|
}
|
|
}
|
|
else
|
|
%canPickup = true;
|
|
|
|
if(%canPickup)
|
|
{
|
|
if(%col.inv[%ammoName] < %aMax)
|
|
{
|
|
%col.incInventory(%ammoName, $AmmoIncrement[%ammoName]);
|
|
serverPlay3D(ItemPickupSound, %col.getTransform());
|
|
%obj.respawn();
|
|
if (%col.client > 0)
|
|
messageClient(%col.client, 'MsgItemPickup', '\c0You picked up %1.', %data.pickUpName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------- Specific turret functions
|
|
|
|
function SentryTurret::onAdd(%data, %obj)
|
|
{
|
|
Parent::onAdd(%data, %obj);
|
|
|
|
//error("error");
|
|
%obj.mountImage(%data.barrel, 0, true);
|
|
}
|
|
|
|
function TurretDeployedCamera::onAdd(%this, %obj)
|
|
{
|
|
Parent::onAdd(%this, %obj);
|
|
%obj.mountImage(DeployableCameraBarrel, 0, true);
|
|
%obj.setRechargeRate(%this.rechargeRate);
|
|
}
|
|
|
|
function TurretDeployedCamera::onDestroyed(%this, %obj, %prevState)
|
|
{
|
|
Parent::onDestroyed(%this, %obj, %prevState);
|
|
$TeamDeployedCount[%obj.team, DeployedCamera]--;
|
|
// doesn't seem to delete itself, so...
|
|
%obj.schedule(500, "delete");
|
|
}
|
|
|
|
function ScoutFlyer::onTrigger(%data, %obj, %trigger, %state)
|
|
{
|
|
// data = ScoutFlyer datablock
|
|
// obj = ScoutFlyer object number
|
|
// trigger = 0 for "fire", 1 for "jump", 3 for "thrust"
|
|
// state = 1 for firing, 0 for not firing
|
|
if(%trigger == 0)
|
|
{
|
|
switch (%state) {
|
|
case 0:
|
|
%obj.fireWeapon = false;
|
|
%obj.setImageTrigger(2, false);
|
|
%obj.setImageTrigger(3, false);
|
|
case 1:
|
|
%obj.fireWeapon = true;
|
|
if(%obj.nextWeaponFire == 2) {
|
|
%obj.setImageTrigger(2, true);
|
|
%obj.setImageTrigger(3, false);
|
|
}
|
|
else {
|
|
%obj.setImageTrigger(2, false);
|
|
%obj.setImageTrigger(3, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function ScoutFlyer::playerDismounted(%data, %obj, %player)
|
|
{
|
|
%obj.fireWeapon = false;
|
|
%obj.setImageTrigger(2, false);
|
|
%obj.setImageTrigger(3, false);
|
|
setTargetSensorGroup(%obj.getTarget(), %obj.team);
|
|
}
|
|
|
|
function ScoutChaingunImage::onFire(%data,%obj,%slot)
|
|
{
|
|
// obj = ScoutFlyer object number
|
|
// slot = 2
|
|
|
|
Parent::onFire(%data,%obj,%slot);
|
|
%obj.nextWeaponFire = 3;
|
|
schedule(%data.fireTimeout, 0, "fireNextGun", %obj);
|
|
}
|
|
|
|
function ScoutChaingunPairImage::onFire(%data,%obj,%slot)
|
|
{
|
|
// obj = ScoutFlyer object number
|
|
// slot = 3
|
|
|
|
Parent::onFire(%data,%obj,%slot);
|
|
%obj.nextWeaponFire = 2;
|
|
schedule(%data.fireTimeout, 0, "fireNextGun", %obj);
|
|
}
|
|
|
|
function fireNextGun(%obj)
|
|
{
|
|
if(%obj.fireWeapon)
|
|
{
|
|
if(%obj.nextWeaponFire == 2)
|
|
{
|
|
%obj.setImageTrigger(2, true);
|
|
%obj.setImageTrigger(3, false);
|
|
}
|
|
else
|
|
{
|
|
%obj.setImageTrigger(2, false);
|
|
%obj.setImageTrigger(3, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
%obj.setImageTrigger(2, false);
|
|
%obj.setImageTrigger(3, false);
|
|
}
|
|
}
|
|
|
|
function ScoutChaingunImage::onTriggerDown(%this, %obj, %slot)
|
|
{
|
|
}
|
|
|
|
function ScoutChaingunImage::onTriggerUp(%this, %obj, %slot)
|
|
{
|
|
}
|
|
|
|
function ScoutChaingunImage::onMount(%this, %obj, %slot)
|
|
{
|
|
// %obj.setImageAmmo(%slot,true);
|
|
}
|
|
|
|
function ScoutChaingunPairImage::onMount(%this, %obj, %slot)
|
|
{
|
|
// %obj.setImageAmmo(%slot,true);
|
|
}
|
|
|
|
function ScoutChaingunImage::onUnmount(%this,%obj,%slot)
|
|
{
|
|
}
|
|
|
|
function ScoutChaingunPairImage::onUnmount(%this,%obj,%slot)
|
|
{
|
|
}
|
|
|
|
|
|
function BomberTurret::onDamage(%data, %obj)
|
|
{
|
|
%newDamageVal = %obj.getDamageLevel();
|
|
if(%obj.lastDamageVal !$= "")
|
|
if(isObject(%obj.getObjectMount()) && %obj.lastDamageVal > %newDamageVal)
|
|
%obj.getObjectMount().setDamageLevel(%newDamageVal);
|
|
%obj.lastDamageVal = %newDamageVal;
|
|
}
|
|
|
|
function BomberTurret::damageObject(%this, %damageObj, %projectile, %amount, %damageType)
|
|
{
|
|
//If vehicle turret is hit then apply damage to the vehicle
|
|
%vehicle = %damageObj.getObjectMount();
|
|
%vehicle.getDataBlock().damageObject(%vehicle, %projectile, %amount, %damageType);
|
|
}
|
|
|
|
function VehicleTurret::onEndSequence(%data, %obj, %thread)
|
|
{
|
|
if($DeployThread == %thread)
|
|
%obj.stopThread($DeployThread);
|
|
}
|
|
|
|
function BomberTurret::onTrigger(%data, %obj, %trigger, %state)
|
|
{
|
|
//error("onTrigger: trigger = " @ %trigger @ ", state = " @ %state);
|
|
//error("obj = " @ %obj @ ", class " @ %obj.getClassName());
|
|
switch (%trigger)
|
|
{
|
|
case 0:
|
|
%obj.fireTrigger = %state;
|
|
if(%obj.selectedWeapon == 1)
|
|
{
|
|
%obj.setImageTrigger(4, false);
|
|
if(%obj.getImageTrigger(6))
|
|
{
|
|
%obj.setImageTrigger(6, false);
|
|
ShapeBaseImageData::deconstruct(%obj.getMountedImage(6), %obj);
|
|
}
|
|
if(%state)
|
|
%obj.setImageTrigger(2, true);
|
|
else
|
|
%obj.setImageTrigger(2, false);
|
|
}
|
|
else if(%obj.selectedWeapon == 2)
|
|
{
|
|
%obj.setImageTrigger(2, false);
|
|
if(%obj.getImageTrigger(6))
|
|
{
|
|
%obj.setImageTrigger(6, false);
|
|
ShapeBaseImageData::deconstruct(%obj.getMountedImage(6), %obj);
|
|
}
|
|
if(%state)
|
|
%obj.setImageTrigger(4, true);
|
|
else
|
|
%obj.setImageTrigger(4, false);
|
|
}
|
|
else
|
|
{
|
|
%obj.setImageTrigger(2, false);
|
|
%obj.setImageTrigger(4, false);
|
|
if(%state)
|
|
%obj.setImageTrigger(6, true);
|
|
else
|
|
{
|
|
%obj.setImageTrigger(6, false);
|
|
BomberTargetingImage::deconstruct(%obj.getMountedImage(6), %obj);
|
|
}
|
|
}
|
|
|
|
case 2:
|
|
if(%state)
|
|
{
|
|
%obj.getDataBlock().playerDismount(%obj);
|
|
}
|
|
}
|
|
}
|
|
|
|
function BomberTurret::playerDismount(%data, %obj)
|
|
{
|
|
//Passenger Exiting
|
|
%obj.fireTrigger = 0;
|
|
%obj.setImageTrigger(2, false);
|
|
%obj.setImageTrigger(4, false);
|
|
if(%obj.getImageTrigger(6))
|
|
{
|
|
%obj.setImageTrigger(6, false);
|
|
ShapeBaseImageData::deconstruct(%obj.getMountedImage(6), %obj);
|
|
}
|
|
%client = %obj.getControllingClient();
|
|
commandToClient(%client, 'endBomberSight');
|
|
// %client.player.setControlObject(%client.player);
|
|
%client.player.mountVehicle = false;
|
|
// %client.player.getDataBlock().doDismount(%client.player);
|
|
if(%client.player.getState() !$= "Dead")
|
|
%client.player.mountImage(%client.player.lastWeapon, $WeaponSlot);
|
|
setTargetSensorGroup(%obj.getTarget(), 0);
|
|
setTargetNeverVisMask(%obj.getTarget(), 0xffffffff);
|
|
}
|
|
|
|
//function BomberTurret::getHudNum(%data, %num)
|
|
//{
|
|
// if(%num == 1)
|
|
// return 0;
|
|
// else
|
|
// return 4;
|
|
//}
|
|
|
|
function AIAimingTurretBarrel::onFire(%this,%obj,%slot)
|
|
{
|
|
}
|
|
|
|
function BomberBombImage::onUnmount(%this,%obj,%slot)
|
|
{
|
|
}
|
|
|
|
function BomberBombPairImage::onUnmount(%this,%obj,%slot)
|
|
{
|
|
}
|
|
|
|
function BomberTurretBarrel::onTriggerDown(%this, %obj, %slot)
|
|
{
|
|
%obj.turretBarrelSchedule = %obj.schedule(300, "setImageTrigger", 3, true);
|
|
}
|
|
|
|
function BomberTurretBarrel::onTriggerUp(%this, %obj, %slot)
|
|
{
|
|
cancel(%obj.turretBarrelSchedule);
|
|
%obj.setImageTrigger( 3, false);
|
|
}
|
|
|
|
function BomberTurretBarrelPair::onMount(%this, %obj, %slot)
|
|
{
|
|
// %obj.setImageAmmo(%slot,true);
|
|
}
|
|
|
|
function BomberTurretBarrel::onMount(%this, %obj, %slot)
|
|
{
|
|
// %obj.setImageAmmo(%slot,true);
|
|
}
|
|
|
|
|
|
function BomberBombImage::onTriggerDown(%this, %obj, %slot)
|
|
{
|
|
%obj.schedule(500, "setImageTrigger", 5, true);
|
|
}
|
|
|
|
function BomberBombImage::onTriggerUp(%this, %obj, %slot)
|
|
{
|
|
%obj.schedule(600, "setImageTrigger", 5, false);
|
|
}
|
|
|
|
function BomberBombPairImage::onMount(%this, %obj, %slot)
|
|
{
|
|
// %obj.setImageAmmo(%slot,true);
|
|
}
|
|
|
|
function BomberBombImage::onMount(%this, %obj, %slot)
|
|
{
|
|
}
|
|
|
|
function BomberBombImage::onUnmount(%this,%obj,%slot)
|
|
{
|
|
}
|
|
|
|
function BomberBombPairImage::onUnmount(%this,%obj,%slot)
|
|
{
|
|
}
|
|
|
|
function MobileTurretBase::onAdd(%this, %obj)
|
|
{
|
|
Parent::onAdd(%this, %obj);
|
|
setTargetSensorGroup(%obj.target, %obj.team);
|
|
setTargetNeverVisMask(%obj.target, 0xffffffff);
|
|
}
|
|
|
|
function MobileTurretBase::onDamage(%data, %obj)
|
|
{
|
|
%newDamageVal = %obj.getDamageLevel();
|
|
if(%obj.lastDamageVal !$= "")
|
|
if(isObject(%obj.getObjectMount()) && %obj.lastDamageVal > %newDamageVal)
|
|
%obj.getObjectMount().setDamageLevel(%newDamageVal);
|
|
%obj.lastDamageVal = %newDamageVal;
|
|
}
|
|
|
|
function MobileTurretBase::damageObject(%this, %targetObject, %sourceObject, %position, %amount, %damageType)
|
|
{
|
|
//If vehicle turret is hit then apply damage to the vehicle
|
|
%vehicle = %targetObject.getObjectMount();
|
|
if(%vehicle)
|
|
%vehicle.getDataBlock().damageObject(%vehicle, %sourceObject, %position, %amount, %damageType);
|
|
}
|
|
|
|
function MobileTurretBase::onEndSequence(%data, %obj, %thread)
|
|
{
|
|
//Used so that the parent wont be called..
|
|
}
|
|
|
|
function AssaultPlasmaTurret::onDamage(%data, %obj)
|
|
{
|
|
%newDamageVal = %obj.getDamageLevel();
|
|
if(%obj.lastDamageVal !$= "")
|
|
if(isObject(%obj.getObjectMount()) && %obj.lastDamageVal > %newDamageVal)
|
|
%obj.getObjectMount().setDamageLevel(%newDamageVal);
|
|
%obj.lastDamageVal = %newDamageVal;
|
|
}
|
|
|
|
function AssaultPlasmaTurret::damageObject(%this, %damageObj, %projectile, %amount, %damageType)
|
|
{
|
|
//If vehicle turret is hit then apply damage to the vehicle
|
|
%vehicle = %damageObj.getObjectMount();
|
|
%vehicle.getDataBlock().damageObject(%vehicle, %projectile, %amount, %damageType);
|
|
}
|
|
|
|
function AssaultPlasmaTurret::onTrigger(%data, %obj, %trigger, %state)
|
|
{
|
|
switch (%trigger) {
|
|
case 0:
|
|
%obj.fireTrigger = %state;
|
|
if(%obj.selectedWeapon == 1)
|
|
{
|
|
%obj.setImageTrigger(4, false);
|
|
if(%state)
|
|
%obj.setImageTrigger(2, true);
|
|
else
|
|
%obj.setImageTrigger(2, false);
|
|
}
|
|
else
|
|
{
|
|
%obj.setImageTrigger(2, false);
|
|
if(%state)
|
|
%obj.setImageTrigger(4, true);
|
|
else
|
|
%obj.setImageTrigger(4, false);
|
|
}
|
|
case 2:
|
|
if(%state)
|
|
{
|
|
%obj.getDataBlock().playerDismount(%obj);
|
|
}
|
|
}
|
|
}
|
|
|
|
function AssaultPlasmaTurret::playerDismount(%data, %obj)
|
|
{
|
|
//Passenger Exiting
|
|
%obj.fireTrigger = 0;
|
|
%obj.setImageTrigger(2, false);
|
|
%obj.setImageTrigger(4, false);
|
|
%client = %obj.getControllingClient();
|
|
// %client.setControlObject(%client.player);
|
|
%client.player.mountImage(%client.player.lastWeapon, $WeaponSlot);
|
|
%client.player.mountVehicle = false;
|
|
setTargetSensorGroup(%obj.getTarget(), 0);
|
|
setTargetNeverVisMask(%obj.getTarget(), 0xffffffff);
|
|
// %client.player.getDataBlock().doDismount(%client.player);
|
|
}
|
|
|
|
//function AssaultPlasmaTurret::getHudNum(%data, %num)
|
|
//{
|
|
// if(%num == 1)
|
|
// return 1;
|
|
// else
|
|
// return 3;
|
|
//}
|
|
|
|
|
|
// ------------------------------------------
|
|
// camera functions
|
|
// ------------------------------------------
|
|
|
|
$CameraDeployTime = 1000;
|
|
$CameraDeployCheckMax = 6;
|
|
$CameraMinVelocity = 0.1;
|
|
|
|
function CameraGrenadeThrown::onThrow(%this, %gren)
|
|
{
|
|
// schedule a check to see if the camera is at rest but not deployed
|
|
%gren.checkCount = 0;
|
|
%gren.velocCheck = %this.schedule($CameraDeployTime, "checkCameraDeploy", %gren);
|
|
}
|
|
|
|
function CameraGrenadeThrown::onStickyCollision(%data, %obj)
|
|
{
|
|
cancel(%obj.velocCheck);
|
|
%pos = %obj.getLastStickyPos();
|
|
%norm = %obj.getLastStickyNormal();
|
|
|
|
%intAngle = getTerrainAngle(%norm); // staticShape.cs
|
|
%rotAxis = vectorNormalize(vectorCross(%norm, "0 0 1"));
|
|
if (getWord(%norm, 2) == 1 || getWord(%norm, 2) == -1)
|
|
%rotAxis = vectorNormalize(vectorCross(%norm, "0 1 0"));
|
|
|
|
%rotation = %rotAxis @ " " @ %intAngle;
|
|
%dcSucc = activateCamera(%pos, %rotation, %obj.sourceObject, %obj.sourceObject.team);
|
|
if(%dcSucc == 0)
|
|
messageClient(%obj.sourceObject.client, 'MsgDeployFailed', '\c2Your team\'s control network has reached its capacity for this item.~wfx/misc/misc.error.wav');
|
|
%obj.schedule(50,"delete");
|
|
}
|
|
|
|
function CameraGrenadeThrown::checkCameraDeploy(%this, %gren)
|
|
{
|
|
%gren.checkCount++;
|
|
if(VectorLen(%gren.getVelocity()) < $CameraMinVelocity)
|
|
{
|
|
// camera has come to rest but not deployed -- probably on a staticshape (station, gen, etc)
|
|
// no resolution, so get rid of it
|
|
%gren.schedule(50, "delete");
|
|
}
|
|
else if(%gren.checkCount >= $CameraDeployCheckMax)
|
|
{
|
|
// camera's still moving but it's been check several times -- it was thrown from too great
|
|
// a height or off the edge of the world -- delete it
|
|
%gren.schedule(50, "delete");
|
|
}
|
|
else
|
|
{
|
|
// check back in a little while
|
|
%gren.velocCheck = %this.schedule($CameraDeployTime, "checkCameraDeploy", %gren);
|
|
}
|
|
}
|
|
|
|
function activateCamera(%position, %rotation, %sourceObj, %team)
|
|
{
|
|
if($TeamDeployedCount[%team, DeployedCamera] >= $TeamDeployableMax[DeployedCamera])
|
|
{
|
|
// team has too many cameras deployed already, don't deploy this one
|
|
return 0;
|
|
}
|
|
%dCam = new Turret()
|
|
{
|
|
dataBlock = "TurretDeployedCamera";
|
|
team = %team;
|
|
needsNoPower = true;
|
|
owner = %sourceObj.client;
|
|
ownerHandle = %sourceObj.client.handle;
|
|
position = %position;
|
|
rotation = %rotation;
|
|
};
|
|
addToDeployGroup(%dCam);
|
|
|
|
if(%dCam.getTarget() != -1)
|
|
setTargetSensorGroup(%dCam.getTarget(), %team);
|
|
|
|
%dCam.playAudio($DeploySound, CameraGrenadeAttachSound);
|
|
%dCam.deploy();
|
|
%dCam.playThread($AmbientThread, "ambient");
|
|
|
|
// increment team's deployed count for cameras
|
|
$TeamDeployedCount[%team, DeployedCamera]++;
|
|
return 1;
|
|
}
|
|
|
|
function FlareGrenade::onUse(%this, %obj)
|
|
{
|
|
// a stripped-down version of HandInventory::onUse from weapons.cs
|
|
if(Game.handInvOnUse(%data, %obj)) {
|
|
%obj.decInventory(%this, 1);
|
|
%p = new FlareProjectile() {
|
|
dataBlock = FlareGrenadeProj;
|
|
initialDirection = %obj.getEyeVector();
|
|
initialPosition = getBoxCenter(%obj.getWorldBox());
|
|
sourceObject = %obj;
|
|
sourceSlot = 0;
|
|
};
|
|
FlareSet.add(%p);
|
|
MissionCleanup.add(%p);
|
|
serverPlay3D(GrenadeThrowSound, getBoxCenter(%obj.getWorldBox()));
|
|
%p.schedule(6000, "delete");
|
|
// miscellaneous grenade-throwing cleanup stuff
|
|
%obj.lastThrowTime[%data] = getSimTime();
|
|
%obj.throwStrength = 0;
|
|
}
|
|
}
|
|
|
|
// uncomment when explosion type can be set from script (dont want underwater explosion here)
|
|
//function grenadeOnEnterLiquid(%data, %obj, %coverage, %type, %flash)
|
|
//{
|
|
// // 4: Lava
|
|
// // 5: Hot Lava
|
|
// // 6: Crusty Lava
|
|
// if(%type >=4 && %type <= 6)
|
|
// {
|
|
// if(%obj.getDamageState() !$= "Destroyed")
|
|
// {
|
|
// cancel(%obj.detThread);
|
|
// if(%flash)
|
|
// detonateFlashGrenade(%obj);
|
|
// else
|
|
// detonateGrenade(%obj);
|
|
// return(true);
|
|
// }
|
|
// }
|
|
//
|
|
// // flash grenades do not ignore quicksand
|
|
// if((%type == 7) && !%flash)
|
|
// return(true);
|
|
//
|
|
// return(false);
|
|
//}
|
|
|
|
function GrenadeThrown::onThrow(%this, %gren)
|
|
{
|
|
AIGrenadeThrown(%gren);
|
|
%gren.detThread = schedule(1500, %gren, "detonateGrenade", %gren);
|
|
}
|
|
|
|
//function GrenadeThrown::onEnterLiquid(%data, %obj, %coverage, %type)
|
|
//{
|
|
// if(!grenadeOnEnterLiquid(%data, %obj, %coverage, %type, false))
|
|
// Parent::onEnterLiquid(%data, %obj, %coverage, %type);
|
|
//}
|
|
|
|
function ConcussionGrenadeThrown::onThrow(%this, %gren)
|
|
{
|
|
AIGrenadeThrown(%gren);
|
|
%gren.detThread = schedule(2000, %gren, "detonateGrenade", %gren);
|
|
}
|
|
|
|
//function ConcussionGrenadeThrown::onEnterLiquid(%data, %obj, %coverage, %type)
|
|
//{
|
|
// if(!grenadeOnEnterLiquid(%data, %obj, %coverage, %type, false))
|
|
// Parent::onEnterLiquid(%data, %obj, %coverage, %type);
|
|
//}
|
|
|
|
function detonateGrenade(%obj)
|
|
{
|
|
%obj.setDamageState(Destroyed);
|
|
%data = %obj.getDataBlock();
|
|
RadiusExplosion( %obj, %obj.getPosition(), %data.damageRadius, %data.indirectDamage,
|
|
%data.kickBackStrength, %obj.sourceObject, %data.radiusDamageType);
|
|
%obj.schedule(500,"delete");
|
|
}
|
|
|
|
function FlashGrenadeThrown::onThrow(%this, %gren)
|
|
{
|
|
%gren.detThread = schedule(2000, %gren, "detonateFlashGrenade", %gren);
|
|
}
|
|
|
|
//function FlashGrenadeThrown::onEnterLiquid(%data, %obj, %coverage, %type)
|
|
//{
|
|
// if(!grenadeOnEnterLiquid(%data, %obj, %coverage, %type, true))
|
|
// Parent::onEnterLiquid(%data, %obj, %coverage, %type);
|
|
//}
|
|
|
|
function detonateFlashGrenade(%hg)
|
|
{
|
|
%thrower = %hg.sourceObject.client;
|
|
%hg.setDamageState(Destroyed);
|
|
%hgt = %hg.getTransform();
|
|
%plX = firstword(%hgt);
|
|
%plY = getWord(%hgt, 1);
|
|
%plZ = getWord(%hgt, 2);
|
|
%pos = %plX @ " " @ %plY @ " " @ %plZ;
|
|
//all this stuff below ripped from projectiles.cs
|
|
|
|
InitContainerRadiusSearch(%pos, 100.0, $TypeMasks::PlayerObjectType |
|
|
$TypeMasks::TurretObjectType);
|
|
|
|
while ((%damage = containerSearchNext()) != 0)
|
|
{
|
|
%dist = containerSearchCurrDist();
|
|
|
|
%eyeXF = %damage.getEyeTransform();
|
|
%epX = firstword(%eyeXF);
|
|
%epY = getWord(%eyeXF, 1);
|
|
%epZ = getWord(%eyeXF, 2);
|
|
%eyePos = %epX @ " " @ %epY @ " " @ %epZ;
|
|
%eyeVec = %damage.getEyeVector();
|
|
|
|
// Make sure we can see the thing...
|
|
if (ContainerRayCast(%eyePos, %pos, $TypeMasks::TerrainObjectType |
|
|
$TypeMasks::InteriorObjectType |
|
|
$TypeMasks::StaticObjectType, %damage) !$= "0")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
%distFactor = 1.0;
|
|
if (%dist >= 100)
|
|
%distFactor = 0.0;
|
|
else if (%dist >= 20) {
|
|
%distFactor = 1.0 - ((%dist - 20.0) / 80.0);
|
|
}
|
|
|
|
%dif = VectorNormalize(VectorSub(%pos, %eyePos));
|
|
%dot = VectorDot(%eyeVec, %dif);
|
|
|
|
%difAcos = mRadToDeg(mAcos(%dot));
|
|
%dotFactor = 1.0;
|
|
if (%difAcos > 60)
|
|
%dotFactor = ((1.0 - ((%difAcos - 60.0) / 120.0)) * 0.2) + 0.3;
|
|
else if (%difAcos > 45)
|
|
%dotFactor = ((1.0 - ((%difAcos - 45.0) / 15.0)) * 0.5) + 0.5;
|
|
|
|
%totalFactor = %dotFactor * %distFactor;
|
|
%prevWhiteOut = %damage.getWhiteOut();
|
|
|
|
if(!%prevWhiteOut)
|
|
if(!$teamDamage)
|
|
{
|
|
error("checking for message");
|
|
if(%damage.client != %thrower && %damage.client.team == %thrower.team)
|
|
messageClient(%damage.client, 'teamWhiteOut', '\c1You were hit by %1\'s whiteout grenade.', getTaggedString(%thrower.name));
|
|
}
|
|
|
|
%damage.setWhiteOut( %prevWhiteOut + %totalFactor);
|
|
}
|
|
%hg.schedule(500, "delete");
|
|
}
|
|
|
|
// ----------------------------------------------
|
|
// mine functions
|
|
// ----------------------------------------------
|
|
|
|
|
|
function MineDeployed::onThrow(%this, %mine, %thrower)
|
|
{
|
|
%mine.armed = false;
|
|
%mine.damaged = 0;
|
|
%mine.detonated = false;
|
|
%mine.depCount = 0;
|
|
schedule(1500, %mine, "deployMineCheck", %mine, %thrower);
|
|
}
|
|
|
|
function deployMineCheck(%mineObj, %player)
|
|
{
|
|
if(%mineObj.depCount > %mineObj.getDatablock().maxDepCount)
|
|
explodeMine(%mineObj, true);
|
|
|
|
// wait until the mine comes to rest
|
|
if(%mineObj.getVelocity() $= "0 0 0")
|
|
{
|
|
// 2-second delay before mine is armed -- let deploy thread play out etc.
|
|
schedule(%mineObj.getDatablock().armTime, %mineObj, "armDeployedMine", %mineObj);
|
|
|
|
|
|
// check for other deployed mines in the vicinity
|
|
InitContainerRadiusSearch(%mineObj.getWorldBoxCenter(), %mineObj.getDatablock().spacing, $TypeMasks::ItemObjectType);
|
|
while((%itemObj = containerSearchNext()) != 0)
|
|
{
|
|
if(%itemObj == %mineObj)
|
|
continue;
|
|
%ioType = %itemObj.getDatablock().getName();
|
|
if(%ioType $= "MineDeployed")
|
|
schedule(100, %mineObj, "explodeMine", %mineObj, true);
|
|
else
|
|
continue;
|
|
}
|
|
// play "deploy" thread
|
|
%mineObj.playThread(0, "deploy");
|
|
serverPlay3D(MineDeploySound, %mineObj.getTransform());
|
|
%mineTeam = %mineObj.sourceObject.team;
|
|
$TeamDeployedCount[%mineTeam, MineDeployed]++;
|
|
if($TeamDeployedCount[%mineTeam, MineDeployed] > $TeamDeployableMax[MineDeployed])
|
|
{
|
|
messageClient( %player.client, '', 'Maximum allowable mines deployed.' );
|
|
schedule(100, %mineObj, "explodeMine", %mineObj, true);
|
|
}
|
|
else
|
|
{
|
|
//start the thread that keeps checking for objects near the mine...
|
|
mineCheckVicinity(%mineObj);
|
|
|
|
//let the AI know *after* it's come to rest...
|
|
AIDeployMine(%mineObj);
|
|
|
|
//let the game know there's a deployed mine
|
|
Game.notifyMineDeployed(%mineObj);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//schedule this deploy check again a little later
|
|
%mineObj.depCount++;
|
|
schedule(500, %mineObj, "deployMineCheck", %mineObj, %player);
|
|
}
|
|
}
|
|
|
|
function armDeployedMine(%mine)
|
|
{
|
|
%mine.armed = true;
|
|
}
|
|
|
|
function mineCheckVicinity(%mine)
|
|
{
|
|
// this function is called after the mine has been deployed. It will check the
|
|
// immediate area around the mine (2.5 meters at present) for players or vehicles
|
|
// passing by, and detonate if any are found. This is to extend the range of the
|
|
// mine so players don't have to collide with them to set them off.
|
|
|
|
// don't bother to check if mine isn't armed yet
|
|
if(%mine.armed)
|
|
// don't keep checking if mine is already detonating
|
|
if(!%mine.boom)
|
|
{
|
|
// the actual check for objects in the area
|
|
%mineLoc = %mine.getWorldBoxCenter();
|
|
%masks = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType;
|
|
%detonateRange = %mine.getDatablock().proximity;
|
|
|
|
InitContainerRadiusSearch(%mineLoc, %detonateRange, %masks);
|
|
while((%tgt = containerSearchNext()) != 0)
|
|
{
|
|
%mine.detonated = true;
|
|
schedule(50, %mine, "explodeMine", %mine, false);
|
|
break;
|
|
}
|
|
}
|
|
// if nothing set off the mine, schedule another check
|
|
if(!%mine.detonated)
|
|
schedule(300, %mine, "mineCheckVicinity", %mine);
|
|
}
|
|
|
|
function MineDeployed::onCollision(%data, %obj, %col)
|
|
{
|
|
// don't detonate if mine isn't armed yet
|
|
if(!%obj.armed)
|
|
return;
|
|
|
|
// don't detonate if mine is already detonating
|
|
if(%obj.boom)
|
|
return;
|
|
|
|
//check to see what it is that collided with the mine
|
|
%struck = %col.getClassName();
|
|
if(%struck $= "Player" || %struck $= "WheeledVehicle" || %struck $= "FlyingVehicle")
|
|
{
|
|
//error("Mine detonated due to collision with #"@%col@" ("@%struck@"); armed = "@%obj.armed);
|
|
explodeMine(%obj, false);
|
|
}
|
|
}
|
|
|
|
function explodeMine(%mo, %noDamage)
|
|
{
|
|
%mo.noDamage = %noDamage;
|
|
%mo.setDamageState(Destroyed);
|
|
}
|
|
|
|
function MineDeployed::damageObject(%data, %targetObject, %sourceObject, %position, %amount, %damageType)
|
|
{
|
|
if(!%targetObject.armed)
|
|
return;
|
|
|
|
if(%targetObject.boom)
|
|
return;
|
|
|
|
%targetObject.damaged += %amount;
|
|
|
|
if(%targetObject.damaged >= %data.maxDamage)
|
|
%targetObject.setDamageState(Destroyed);
|
|
}
|
|
|
|
function MineDeployed::onDestroyed(%data, %obj, %lastState)
|
|
{
|
|
%obj.boom = true;
|
|
%mineTeam = %obj.sourceObject.team;
|
|
$TeamDeployedCount[%mineTeam, MineDeployed]--;
|
|
// %noDamage is a boolean flag -- don't want to set off all other mines in
|
|
// vicinity if there's a "mine overload", so apply no damage/impulse if true
|
|
if(!%obj.noDamage)
|
|
RadiusExplosion(%obj, %obj.getPosition(), %data.damageRadius, %data.indirectDamage,
|
|
%data.kickBackStrength, %obj.sourceObject, %data.radiusDamageType);
|
|
|
|
%obj.schedule(600, "delete");
|
|
} |