Files
dsrc/sku.0/sys.server/compiled/game/script/library/advanced_turret.scriptlib
T
Redacted by Stellabellum INC b93530b6c8 Fixed the Following:
Updated Generic Spawner Script
Removed OP Buff from GCW City Generals
Turrets in Bestine no longer shoot Bounty Hunters
GCW Defensive Generals are Invulnerable until the last 15 minutes of the invasion.
Fixed GM Kill command
2015-02-13 18:28:39 -08:00

729 lines
17 KiB
Plaintext

/***** INCLUDES ********************************************************/
include library.callable;
include library.factions;
include library.pclib;
include library.stealth;
include library.trace;
include library.utils;
include library.vehicle;
include library.weapons;
/***** CONSTANTS *******************************************************/
const string ALERT_VOLUME_NAME = "turretAggroVolume";
const float DEFAULT_TURRET_RANGE = 64.0f;
const float RANGE_TOO_CLOSE = 10f;
const string VAR_TURRET_BASE = "turret";
const string IS_ACTIVE = VAR_TURRET_BASE + ".isActive";
const string TARGETS = VAR_TURRET_BASE + ".targetList";
const string TURRET_FRIEND = VAR_TURRET_BASE + ".isFriend"; // set this on a potential target to make the turret ignore them. friends never get attacked
const string IS_ENGAGED = VAR_TURRET_BASE + ".isTrackingTarget";
const string IS_OUTDOORS = VAR_TURRET_BASE + ".isOutdoors";
const string FACTION = VAR_TURRET_BASE + ".faction";
const string RANGE = VAR_TURRET_BASE + ".range";
const string MY_WEAPON = VAR_TURRET_BASE + ".myWeapon";
const int TYPE_BLOCK = 1;
const int TYPE_DISH = 2;
const int TYPE_TOWER = 3;
const int SIZE_SMALL = 1;
const int SIZE_MEDIUM = 2;
const int SIZE_LARGE = 3;
const int SIZE_MINI = 4;
obj_id createTurret(location loc, float yaw, int minDamage, int maxDamage, float attackSpeed, float range)
{
return createTurret(loc, yaw, TYPE_BLOCK, SIZE_SMALL, DAMAGE_ENERGY, minDamage, maxDamage, range, attackSpeed, "");
}
obj_id createTurret(location loc, float yaw, int type, int size, int damageType, int minDamage, int maxDamage, float range, float attackSpeed, string faction)
{
return createTurret(loc, yaw, TYPE_BLOCK, SIZE_SMALL, DAMAGE_ENERGY, minDamage, maxDamage, 10000, range, attackSpeed, "");
}
obj_id createTurret(location loc, float yaw, int type, int size, int damageType, int minDamage, int maxDamage, int hitpoints, float range, float attackSpeed, string faction)
{
return createTurret(null, loc, yaw, type, size, damageType, minDamage, maxDamage, hitpoints, range, attackSpeed, faction);
}
obj_id createTurret(obj_id owner, location loc, float yaw, int type, int size, int damageType, int minDamage, int maxDamage, int hitpoints, float range, float attackSpeed, string faction)
{
string template = "object/installation/turret/gcw/adv_turret";
switch(type)
{
case TYPE_BLOCK:
template += "_block";
break;
case TYPE_DISH:
template += "_dish";
break;
case TYPE_TOWER:
template += "_tower";
break;
}
switch(size)
{
case SIZE_MINI:
template += "_mini";
break;
case SIZE_SMALL:
template += "_sm";
break;
case SIZE_MEDIUM:
if(type == TYPE_DISH)
{
template += "_sm"; // No medium dish exists
}
else
{
template += "_med";
}
break;
case SIZE_LARGE:
template += "_large";
break;
}
switch(damageType)
{
case DAMAGE_ELEMENTAL_HEAT:
template += "_heat";
break;
case DAMAGE_ELEMENTAL_COLD:
template += "_cold";
break;
case DAMAGE_ELEMENTAL_ACID:
template += "_acid";
break;
case DAMAGE_ELEMENTAL_ELECTRICAL:
template += "_electricity";
break;
case DAMAGE_KINETIC:
template += "_kinetic";
break;
default: //DAMAGE_ENERGY
template += "_energy";
break;
}
template += ".iff";
obj_id turret = createObject(template, loc);
if(!isIdValid(turret))
{
return null;
}
setYaw(turret, yaw);
if(isIdValid(owner) && exists(owner))
{
setObjVar(turret, "turret_master", owner);
}
initTurret(turret, faction, damageType, range, minDamage, maxDamage, hitpoints, attackSpeed);
return turret;
}
void activateTurret(obj_id turret)
{
LOG("TURRET", "activateTurret " + turret);
if(!isIdValid(turret))
{
return;
}
obj_id turretWeapon = getTurretWeapon(turret);
if (!isIdValid(turretWeapon))
return;
utils.setScriptVar(turret, IS_ACTIVE, true);
setInvulnerable(turret, false);
pvpSetAttackableOverride(turret, true);
weapons.setWeaponData(turretWeapon);
float range = getFloatObjVar(turret, RANGE);
dictionary dict = new dictionary();
dict.put("range", range);
messageTo(turret, "createTriggerVolume", dict, 0.0f, false);
return;
}
void deactivateTurret(obj_id turret)
{
LOG("TURRET", "deactivateTurret " + turret);
if(!isIdValid(turret))
{
return;
}
stopTrackingTarget(turret);
utils.removeScriptVar(turret, IS_ACTIVE);
setInvulnerable(turret, true);
return;
}
boolean isActive(obj_id turret)
{
if(!isIdValid(turret))
{
return false;
}
if(utils.hasScriptVar(turret, IS_ACTIVE))
{
LOG("TURRET", "Turret " + turret + " is active.");
return true;
}
LOG("TURRET", "Turret " + turret + " is not active.");
return false;
}
// causes the muzzle to track the target. turret must be active before it can start tracking a target
void startTrackingTarget(obj_id turret, obj_id target)
{
LOG("TURRET", "Turret " + turret + " start tracking target " + target);
if(!isIdValid(turret) || !isIdValid(target))
{
return;
}
if(!isActive(turret))
{
LOG("TURRET", "Turret " + turret + " can't track target - turret inactive.");
return;
}
utils.setScriptVar(turret, IS_ENGAGED, target);
//setCombatTarget(turret, target);
return;
}
// stops the turret muzzle from tracking the target
void stopTrackingTarget(obj_id turret)
{
LOG("TURRET", "Turret " + turret + " stop tracking target.");
if(!isIdValid(turret))
{
return;
}
utils.removeScriptVar(turret, IS_ENGAGED);
//setCombatTarget(turret, null);
return;
}
boolean isEngaged(obj_id turret)
{
if(!isIdValid(turret))
{
return false;
}
if(utils.hasScriptVar(turret, IS_ENGAGED))
{
return true;
}
return false;
}
obj_id getCurrentTarget(obj_id turret)
{
if(!isEngaged(turret))
{
return null;
}
return utils.getObjIdScriptVar(turret, IS_ENGAGED);
}
obj_id getTurretWeapon(obj_id turret)
{
if(!isIdValid(turret) || !exists(turret))
{
return null;
}
if(!hasObjVar(turret, MY_WEAPON))
{
return null;
}
return getObjIdObjVar(turret, MY_WEAPON);
}
//
// use factions.FACTION_IMPERIAL, factions.FACTION_REBEL, or a string from datatables/faction/faction.iff
// to set the faction of the turret. the turret does a factions.areFactionsOpposed test before attacking a target.
// set the faction to "" (empty string) to make the turret attack every player regardless of faction
// set the range to -1 to use DEFAULT_TURRET_RANGE
void initTurret(obj_id turret, string faction, int damageType, float range, int minDamage, int maxDamage, int hitpoints, float attackSpeed)
{
detachScript(turret, "systems.turret.turret_ai");
attachScript(turret, "systems.turret.advanced_turret_ai");
boolean isOutdoors = getTopMostContainer(turret) == turret;
setObjVar(turret, IS_OUTDOORS, isOutdoors);
setObjVar(turret, FACTION, faction.equals("")? "renegade" :faction); // setting an empty string in local vars sucks, so we set "renegage" as the all killer faction
setObjVar(turret, RANGE, range == -1f? DEFAULT_TURRET_RANGE : range);
factions.setFaction(turret, faction);
setMaxHitpoints(turret, hitpoints);
setHitpoints(turret, hitpoints);
setObjVar(turret, "pvpCanAttack", 1);
setInvulnerable(turret, false);
string weaponTemplate = "object/weapon/ranged/turret/turret_block_large.iff";
obj_id objWeapon = createObject(weaponTemplate, turret, "");
if(!isIdValid(objWeapon))
{
explodeTurret(turret, turret);
return;
}
setObjVar(turret, MY_WEAPON, objWeapon);
setWeaponAttackSpeed(objWeapon, attackSpeed < 1f? 1f : attackSpeed);
int primaryType = DAMAGE_ENERGY;
int secondaryType = DAMAGE_ELEMENTAL_HEAT;
int primaryMinDamage = 0;
int primaryMaxDamage = 0;
int secondaryDamage = 0;
switch(damageType)
{
case DAMAGE_ELEMENTAL_COLD:
case DAMAGE_ELEMENTAL_ACID:
case DAMAGE_ELEMENTAL_ELECTRICAL:
case DAMAGE_ELEMENTAL_HEAT:
primaryType = DAMAGE_ENERGY;
secondaryType = damageType;
primaryMinDamage = 1;
primaryMaxDamage = 1;
secondaryDamage = (int)((float)minDamage + (float)maxDamage / 2.0f);
break;
case DAMAGE_KINETIC:
case DAMAGE_ENERGY:
primaryType = damageType;
secondaryType = DAMAGE_ELEMENTAL_HEAT;
primaryMinDamage = minDamage;
primaryMaxDamage = maxDamage;
secondaryDamage = 0;
break;
}
setWeaponDamageType(objWeapon, primaryType);
setWeaponElementalType(objWeapon, secondaryType);
setWeaponMinDamage(objWeapon, minDamage);
setWeaponMaxDamage(objWeapon, maxDamage);
setWeaponElementalValue(objWeapon, secondaryDamage);
range_info ri = new range_info();
ri.maxRange = range;
setWeaponRangeInfo(objWeapon, ri);
activateTurret(turret);
return;
}
boolean isValidTarget(obj_id turret, obj_id target)
{
// Both objects must be valid and on the same game server
if(!isIdValid(turret) || !isIdValid(target) || !exists(turret) || !exists(target) )
{
doLogging("isValidTarget", "I or "+target+" is not valid or does not exist: "+isIdValid(turret)+"/"+isIdValid(target)+"/"+exists(turret)+"/"+exists(target));
return false;
}
if(vehicle.isVehicle(target))
{
doLogging("isValidTarget", "Target "+getName(target)+" is a vehicle");
return false;
}
if(stealth.hasInvisibleBuff(target))
{
doLogging("isValidTarget", "Target "+getName(target)+" has a stealth buff");
return false;
}
// can't attack self
if(target == turret)
{
doLogging("isValidTarget", "I'm attempting to attack myself");
return false;
}
float range = hasObjVar(turret, RANGE) ? getFloatObjVar(turret, RANGE) : DEFAULT_TURRET_RANGE;
// Range check
float dist = getDistance(target, turret);
if(dist > range + 1)
{
doLogging("isValidTarget", "Target out of range. dist: " + dist + " range: " + range);
return false;
}
if(utils.hasScriptVar(target, TURRET_FRIEND))
{
doLogging("isValidTarget", "Target is a friend.");
return false;
}
if(isDead(target) || isIncapacitated(target))
{
doLogging("isValidTarget", "Target is dead or incapped");
return false;
}
if(hasScript(turret, "systems.gcw.gcw_turret") && hasScript(target, "ai.smuggler_spawn_enemy"))
{
return false;
//2/1/15: Temp hack so turrets focus on enemy rather than BH NPC's in Bestine
}
if(ai_lib.isAnimal(target) && hasScript(turret, "systems.gcw.gcw_turret"))
{
return false;
//2/1/15: Temp hack so turrets focus on enemy rather than wild creatures.
}
if(isMob(target) && isIdValid(getMaster(target)))
{
obj_id cd = callable.getCallableCD(target);
if(callable.getControlDeviceType(cd) == callable.CALLABLE_TYPE_FAMILIAR)
{
return false;
}
}
obj_id master = getObjIdObjVar(turret, "turret_master");
if(isIdValid(master) && exists(master) && !pvpCanAttack(master, target))
{
return false;
}
string turretFaction = hasObjVar(turret, FACTION) ? getStringObjVar(turret, FACTION) : getBaseFaction(turret);
if(!turretFaction.equals("renegade"))
{
obj_id pvpTarget = target;
if(isMob(target) && !isPlayer(target) && isIdValid(getMaster(target)))
{
pvpTarget = getMaster(target);
}
if(!pvpCanAttack(turret, pvpTarget))
{
doLogging("isValidTarget", "Our factions are not opposed: Self/Target: "+factions.getFaction(turret)+"/"+factions.getFaction(target));
return false;
}
}
return true;
}
string getBaseFaction(obj_id turret)
{
obj_id parentBase = getObjIdObjVar(turret, "hq.defense.parent");
if (!isIdValid(parentBase))
return "renegade";
return getStringObjVar(parentBase, "faction");
}
void addTarget(obj_id turret, obj_id target)
{
if(!isValidTarget(turret, target))
{
doLogging("addTarget", ""+getName(target)+"/"+target+" was invalid");
return;
}
Vector targets = null;
if(!utils.hasScriptVar(turret, TARGETS))
{
targets = new Vector();
}
else
{
targets = utils.getResizeableObjIdBatchScriptVar(turret, TARGETS);
}
if(targets != null && targets.indexOf(target) == -1)
{
targets.add(target);
}
if(targets.size() > 0)
{
utils.setBatchScriptVar(turret, TARGETS, targets);
if(!isEngaged(turret))
{
attackPulse(turret);
}
}
return;
}
void addTargets(obj_id turret, obj_id[] newTargets)
{
Vector targets = null;
if(!utils.hasScriptVar(turret, TARGETS))
{
targets = new Vector();
}
else
{
targets = utils.getResizeableObjIdBatchScriptVar(turret, TARGETS);
}
for(int i = 0; i < newTargets.length; i++)
{
if(!isValidTarget(turret, newTargets[i]) || targets.indexOf(newTargets[i]) != -1)
{
doLogging("addTargets", ""+getName(newTargets[i])+"/"+newTargets[i]+" was invalid or already in my target array");
continue;
}
targets.add(newTargets[i]);
}
if(targets.size() > 0)
{
utils.setBatchScriptVar(turret, TARGETS, targets);
if(!isEngaged(turret))
{
messageTo(turret, "handleTurretAttack", null, 1, false);
}
}
return;
}
void removeTarget(obj_id turret, obj_id target)
{
if(!isIdValid(turret) || !isIdValid(target))
{
doLogging("removeTarget", "Removed "+target);
return;
}
if(!utils.hasScriptVar(turret, TARGETS))
{
return;
}
Vector targets = utils.getResizeableObjIdBatchScriptVar(turret, TARGETS);
obj_id engageTarget = utils.getObjIdScriptVar(turret, IS_ENGAGED);
int idx = targets.indexOf(target);
if(idx > -1)
{
if(isIdValid(engageTarget) && target == engageTarget)
{
stopTrackingTarget(turret);
}
targets.remove(idx);
if(targets.size() == 0)
{
utils.removeBatchScriptVar(turret, TARGETS);
}
else
{
utils.setBatchScriptVar(turret, TARGETS, targets);
}
}
return;
}
boolean handleTurretDamage(obj_id turret, obj_id attacker, obj_id weapon, int dmgAmount)
{
if (!validateAttacker(turret, attacker))
{
doLogging("handleTurretDamage", getName(attacker)+"/"+attacker+" was not a valid attacker.");
return false;
}
int curHP = getHitpoints(turret);
if(curHP < 1)
{
explodeTurret(turret, attacker);
return true;
}
addTarget(turret, attacker);
if(!utils.hasScriptVar(turret, "playingEffect"))
{
int smolder = 2000;
int fire = 1000;
if(curHP < smolder)
{
location death = getLocation(turret);
utils.setScriptVar(turret, "playingEffect", 1);
string effect = "";
if(curHP < fire)
{
effect = "clienteffect/lair_hvy_damage_fire.cef";
}
else
{
effect = "clienteffect/lair_med_damage_smoke.cef";
}
playClientEffectLoc(attacker, effect , death, 0);
messageTo(turret, "effectManager", null, 15, true);
}
}
return true;
}
boolean validateAttacker(obj_id turret, obj_id attacker)
{
obj_id master = getObjIdObjVar(turret, "turret_master");
if(isIdValid(master) && exists(master) && !pvpCanAttack(master, attacker))
{
return false;
}
return pvpIsEnemy(turret, attacker);
}
void explodeTurret(obj_id turret, obj_id killer)
{
location death = getLocation(turret);
deactivateTurret(turret);
playClientEffectLoc(turret, "clienteffect/combat_explosion_lair_large.cef", death, 0);
messageTo(turret, "handleDestroyTurret", null, 2, false);
return;
}
obj_id getGoodTurretTarget(obj_id turret)
{
// see who the last person was that we shot at and see if they are still good
obj_id target = getCurrentTarget(turret);
if(!isValidTarget(turret, target) || isIncapacitated(target) || isDead(target) || !canSee(turret, target) )
{
if(isIncapacitated(target) && !isDead(target))
{
pclib.coupDeGrace(target, turret, false);
}
target = null;
}
else
{
return target;
}
if(!utils.hasScriptVar(turret, TARGETS))
{
return null;
}
//remove incapacitated targets:
Vector targets = utils.getResizeableObjIdBatchScriptVar(turret, TARGETS);
if((targets == null) || (targets.size() == 0))
{
doLogging("getGoodTurretTarget", "I had no target batchvar so I am returning null");
return null;
}
target = null;
while(!isIdValid(target))
{
if(targets.size() < 1)
{
break;
}
target = (obj_id)targets.get(rand(0, targets.size() - 1));
if(!isValidTarget(turret, target) ||
isDead(target) ||
isIncapacitated(target) ||
!canSee(turret, target)|| vehicle.isVehicle(target) || stealth.hasInvisibleBuff(target))
{
targets.removeElement(target);
target = null;
continue;
}
}
if(targets.size() < 1)
{
stopTrackingTarget(turret);
utils.removeBatchScriptVar(turret, TARGETS);
}
else
{
utils.setBatchScriptVar(turret, TARGETS, targets);
}
return target;
}
void attackPulse(obj_id turret)
{
if(!isActive(turret))
{
return;
}
obj_id target = getGoodTurretTarget(turret);
if(!isIdValid(target))
{
stopTrackingTarget(turret);
return;
}
startTrackingTarget(turret, target);
executeAttackAction(turret, target);
}
void executeAttackAction(obj_id turret, obj_id target)
{
obj_id weapon = getTurretWeapon(turret);
if(!isIdValid(weapon))
{
stopTrackingTarget(turret);
}
dictionary params = new dictionary();
params.put("target", target);
messageTo(turret, "turretShot", params, getWeaponAttackSpeed(weapon), false);
return;
}
void doLogging(string section, string message)
{
LOG("doLogging/advanced_turret.scriptlib/"+section, message);
}