mirror of
https://github.com/SWG-Source/dsrc.git
synced 2026-07-31 00:15:54 -04:00
408 lines
14 KiB
Plaintext
408 lines
14 KiB
Plaintext
// ================================================================================
|
|
//
|
|
// spawn.script
|
|
// copyright 2006, Sony Online Entertainment LLC
|
|
//
|
|
// ================================================================================
|
|
|
|
include ai.ai_combat;
|
|
include library.ai_lib;
|
|
include library.buff;
|
|
include library.create;
|
|
include library.groundquests;
|
|
include library.locations;
|
|
include library.utils;
|
|
include library.ship_ai;
|
|
include library.space_quest;
|
|
include library.space_utils;
|
|
include library.space_create;
|
|
include library.space_transition;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
inherits quest.task.ground.base_task;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
const String dataTableColumnCreatureType = "CREATURE_TYPE";
|
|
const String dataTableColumnMinCount = "MIN_COUNT";
|
|
const String dataTableColumnMaxCount = "MAX_COUNT";
|
|
const String dataTableColumnMinDistance = "MIN_DISTANCE";
|
|
const String dataTableColumnMaxDistance = "MAX_DISTANCE";
|
|
const String dataTableColumnMinLevelDifference = "MIN_LEVEL_DIFFERENCE";
|
|
const String dataTableColumnMaxLevelDifference = "MAX_LEVEL_DIFFERENCE";
|
|
const String dataTableColumnGroundStartCombat = "GROUND_START_COMBAT";
|
|
const String dataTableColumnDismountPlayer = "DISMOUNT_PLAYER";
|
|
const String dataTableColumnMountBlockDuration = "MOUNT_BLOCK_DURATION";
|
|
const String dataTableColumnBuffName = "BUFF_NAME";
|
|
|
|
const String dataTableColumnShipType = "SHIP_TYPE";
|
|
const String dataTableColumnShipMinCount = "SHIP_MIN_COUNT";
|
|
const String dataTableColumnShipMaxCount = "SHIP_MAX_COUNT";
|
|
const String dataTableColumnSpaceStartCombat = "SPACE_START_COMBAT";
|
|
const String dataTableColumnHyperspaceBlockDuration = "HYPERSPACE_BLOCK_DURATION";
|
|
|
|
const String dataTableColumnMinStartDelay = "MIN_START_DELAY";
|
|
const String dataTableColumnMaxStartDelay = "MAX_START_DELAY";
|
|
const String dataTableColumnChanceToSkip = "CHANCE_TO_SKIP";
|
|
|
|
const String objvarPlayedTimeEnd = "playedTimeEnd";
|
|
|
|
const String objvarOnCreatureOwner = "quest.owner";
|
|
const String objvarOnCreatureQuestCrc = "quest.questCrc";
|
|
const String objvarOnCreatureTaskId = "quest.taskId";
|
|
const String objvarOnCreatureCount = "quest.count";
|
|
|
|
const String taskType = "spawn";
|
|
const String dot = ".";
|
|
|
|
const float cleanupTime = 300.f;
|
|
const float cleanupRetryTime = 60.f;
|
|
|
|
const String scriptSpawnOnCreature = "quest.task.ground.spawn_on_creature";
|
|
const String scriptSpawnOnShip = "quest.task.ground.spawn_on_ship";
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
trigger OnTaskActivated(int questCrc, int taskId)
|
|
{
|
|
groundquests.questOutputDebugInfo(self, questCrc, taskId, taskType, "OnTaskActivated", taskType + " task activated.");
|
|
|
|
String baseObjVar = groundquests.setBaseObjVar(self, taskType, questGetQuestName(questCrc), taskId);
|
|
|
|
int minStartDelay = Math.max(0, groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnMinStartDelay));
|
|
int maxStartDelay = Math.max(minStartDelay, groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnMaxStartDelay));
|
|
|
|
int timeLeft = 0;
|
|
|
|
if (minStartDelay > 0 && maxStartDelay > 0)
|
|
timeLeft = rand(minStartDelay, maxStartDelay);
|
|
|
|
groundquests.questOutputDebugInfo(self, questCrc, taskId, taskType, "OnTaskActivated", "Spawn will start in " + timeLeft + " seconds.");
|
|
|
|
dictionary params = new dictionary();
|
|
params.put("questCrc", questCrc);
|
|
params.put("taskId", taskId);
|
|
|
|
float playerPlayedTimeWhenTimerEnds = (float)getPlayerPlayedTime(self) + timeLeft;
|
|
setObjVar(self, baseObjVar + "." + objvarPlayedTimeEnd, playerPlayedTimeWhenTimerEnds);
|
|
|
|
messageTo(self, "messageStartQuestSpawn", params, timeLeft, true);
|
|
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
messageHandler messageStartQuestSpawn()
|
|
{
|
|
int questCrc = params.getInt ("questCrc");
|
|
int taskId = params.getInt ("taskId");
|
|
|
|
if(questIsTaskActive(questCrc, taskId, self))
|
|
{
|
|
String baseObjVar = groundquests.getBaseObjVar(self, taskType, questGetQuestName(questCrc), taskId);
|
|
float playerPlayedTimeWhenTimerEnds = getFloatObjVar(self, baseObjVar + "." + objvarPlayedTimeEnd);
|
|
float timeLeft = playerPlayedTimeWhenTimerEnds - (float)getPlayerPlayedTime(self);
|
|
|
|
if(timeLeft > 1)
|
|
{
|
|
messageTo(self, "messageStartQuestSpawn", params, timeLeft, true);
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
|
|
int chanceToSkip = groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnChanceToSkip);
|
|
|
|
int chanceRoll = rand(0, 99);
|
|
|
|
if(chanceToSkip > chanceRoll)
|
|
{
|
|
questCompleteTask(questCrc, taskId, self);
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
|
|
if (isSpaceScene())
|
|
startSpaceQuestSpawn(self, questCrc, taskId);
|
|
else
|
|
startGroundQuestSpawn(self, questCrc, taskId);
|
|
}
|
|
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
void startGroundQuestSpawn(obj_id player, int questCrc, int taskId)
|
|
{
|
|
String creatureType = groundquests.getTaskStringDataEntry(questCrc, taskId, dataTableColumnCreatureType);
|
|
int minCount = groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnMinCount);
|
|
int maxCount = groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnMaxCount);
|
|
float minRadius = groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnMinDistance);
|
|
float maxRadius = groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnMaxDistance);
|
|
boolean shouldDismountPlayer = groundquests.getTaskBoolDataEntry(questCrc, taskId, dataTableColumnDismountPlayer, false);
|
|
int mountBlockDuration = groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnMountBlockDuration);
|
|
String buffName = groundquests.getTaskStringDataEntry(questCrc, taskId, dataTableColumnBuffName);
|
|
|
|
int minLevelDifference = Math.max(0, groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnMinLevelDifference));
|
|
int maxLevelDifference = Math.max(0, groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnMaxLevelDifference));
|
|
boolean doAutoLeveling = minLevelDifference > 0 || maxLevelDifference > 0;
|
|
|
|
location l = null;
|
|
location locTest = getLocation(player);
|
|
|
|
if(!isIdValid(locTest.cell))
|
|
{
|
|
location locA = locTest;
|
|
location locB = locTest;
|
|
|
|
locA.x -= 5;
|
|
locA.y -= 5;
|
|
locA.z -= 5;
|
|
|
|
locB.x += 5;
|
|
locB.y += 5;
|
|
locB.z += 5;
|
|
|
|
// getGoodLocation(float hintX, float hintZ, location searchRectLL, location searchRectUR, boolean dontCheckWater, boolean dontCheckSlope)
|
|
l = getGoodLocation(1, 1, locA, locB, false, true);
|
|
|
|
// Bad location found?
|
|
if(getDistance(l, locTest) < 0.0f || getDistance(l, locTest) > 10.0f)
|
|
{
|
|
questCompleteTask(questCrc, taskId, player);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (shouldDismountPlayer)
|
|
utils.dismountRiderJetpackCheck(player);
|
|
|
|
if (mountBlockDuration > 0)
|
|
utils.setScriptVar(player, "mountBlock", getPlayerPlayedTime(player) + mountBlockDuration);
|
|
|
|
if (buffName != null && buffName.length() > 0)
|
|
buff.applyBuff(player, buffName);
|
|
|
|
if (maxCount < minCount)
|
|
maxCount = minCount;
|
|
|
|
int count = rand(minCount, maxCount);
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
l = null;
|
|
|
|
if(!isIdValid(locTest.cell))
|
|
{
|
|
l = groundquests.getRandom2DLocationAroundPlayer(player, minRadius, maxRadius);
|
|
}
|
|
else
|
|
{
|
|
// handle the case where the player is inside a building
|
|
string strCell = getCellName(locTest.cell);
|
|
obj_id objBuilding = getTopMostContainer(player);
|
|
l = getGoodLocation(objBuilding, strCell);
|
|
}
|
|
|
|
|
|
obj_id creature;
|
|
int creatureLevel = 0;
|
|
|
|
if (doAutoLeveling)
|
|
{
|
|
int minLevel = Math.max(1, getLevel(player) - minLevelDifference);
|
|
int maxLevel = Math.max(minLevel, getLevel(player) + maxLevelDifference);
|
|
|
|
creatureLevel = rand(minLevel, maxLevel);
|
|
|
|
if(creatureLevel > 90)
|
|
{
|
|
creatureLevel = 90;
|
|
}
|
|
else if(creatureLevel < 1)
|
|
{
|
|
creatureLevel = 1;
|
|
}
|
|
|
|
creature = create.createCreature(creatureType, l, creatureLevel, true);
|
|
}
|
|
else
|
|
{
|
|
creature = create.createCreature(creatureType, l, true);
|
|
}
|
|
|
|
setObjVar(creature, objvarOnCreatureOwner, player);
|
|
setObjVar(creature, objvarOnCreatureQuestCrc, questCrc);
|
|
setObjVar(creature, objvarOnCreatureTaskId, taskId);
|
|
setObjVar(creature, objvarOnCreatureCount, i);
|
|
attachScript(creature, scriptSpawnOnCreature);
|
|
|
|
// if we can be talked to, that probably means we shouldn't be attacking.
|
|
if (!hasCondition(creature, CONDITION_CONVERSABLE))
|
|
{
|
|
groundquests.questOutputDebugInfo(player, questCrc, taskId, taskType, "startGroundQuestSpawn",
|
|
"Spawned " + creature + "(" + creatureLevel + ") at [" + l.x + ", " + l.y + ", " + l.z + "] to attack " + player);
|
|
|
|
boolean shouldStartCombat = groundquests.getTaskBoolDataEntry(questCrc, taskId, dataTableColumnGroundStartCombat, false);
|
|
|
|
if (shouldStartCombat)
|
|
startCombat(creature, player);
|
|
}
|
|
}
|
|
|
|
questCompleteTask(questCrc, taskId, player);
|
|
return;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
void startSpaceQuestSpawn(obj_id player, int questCrc, int taskId)
|
|
{
|
|
groundquests.questOutputDebugInfo(player, questCrc, taskId, taskType, "startSpaceQuestSpawn",
|
|
"Space spawn started!");
|
|
|
|
boolean shouldStartCombat = groundquests.getTaskBoolDataEntry(questCrc, taskId, dataTableColumnSpaceStartCombat, false);
|
|
|
|
if (shouldStartCombat && !space_utils.isPlayerShipAttackable(player))
|
|
{
|
|
groundquests.questOutputDebugInfo(player, questCrc, taskId, taskType, "startSpaceQuestSpawn",
|
|
"Spawn failed due to player's ship being unattackable.");
|
|
questFailTask(questCrc, taskId, player);
|
|
return;
|
|
}
|
|
|
|
String baseObjVar = groundquests.getBaseObjVar(player, taskType, questGetQuestName(questCrc), taskId);
|
|
|
|
String shipType = groundquests.getTaskStringDataEntry(questCrc, taskId, dataTableColumnShipType);
|
|
|
|
if (shipType == null || shipType.length() == 0)
|
|
{
|
|
groundquests.questOutputDebugInfo(player, questCrc, taskId, taskType, "startSpaceQuestSpawn",
|
|
"Spawn failed due to starting in space with no shipType defined.");
|
|
questFailTask(questCrc, taskId, player);
|
|
return;
|
|
}
|
|
|
|
int hyperspaceBlockDuration = groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnHyperspaceBlockDuration);
|
|
|
|
if (hyperspaceBlockDuration > 0)
|
|
space_utils.setHyperspaceBlock(player, hyperspaceBlockDuration, true);
|
|
|
|
int minCount = groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnShipMinCount);
|
|
int maxCount = groundquests.getTaskIntDataEntry(questCrc, taskId, dataTableColumnShipMaxCount);
|
|
|
|
if (maxCount < minCount)
|
|
maxCount = minCount;
|
|
|
|
int squad = ship_ai.squadCreateSquadId();
|
|
int count = rand(minCount, maxCount);
|
|
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
transform gloc = getTransform_o2w(space_transition.getContainingShip(player));
|
|
|
|
// Move the starting spot out in front of us.
|
|
float dist = rand(700.f, 800.f);
|
|
vector n = gloc.getLocalFrameK_p().normalize().multiply(dist); // Project a point out in front of us.
|
|
gloc = gloc.move_p(n);
|
|
|
|
// Flip the starting spot around so its facing us.
|
|
gloc = gloc.yaw_l(3.14f);
|
|
|
|
// Find a spot on the IJ plane for deviation in a cone shape.
|
|
vector vi = gloc.getLocalFrameI_p().normalize().multiply(rand(-150.f, 150.f));
|
|
vector vj = gloc.getLocalFrameJ_p().normalize().multiply(rand(-150.f, 150.f));
|
|
vector vd = vi.add(vj);
|
|
gloc = gloc.move_p(vd);
|
|
|
|
obj_id newship = space_create.createShipHyperspace(shipType, gloc);
|
|
ship_ai.unitSetLeashDistance(newship, 16000);
|
|
if (count > 3)
|
|
ship_ai.unitSetSquadId(newship, squad);
|
|
|
|
attachScript(newship, scriptSpawnOnShip);
|
|
|
|
if (shouldStartCombat)
|
|
{
|
|
// This guy can only be harmed by the player or his group.
|
|
setObjVar(newship, "objMissionOwner", player);
|
|
ship_ai.unitAddExclusiveAggro(newship, player);
|
|
dictionary dict = new dictionary ();
|
|
dict.put("player", space_transition.getContainingShip(player));
|
|
messageTo(newship, "spawnAttackPlayerShip", dict, 4.0f, false);
|
|
}
|
|
}
|
|
|
|
// Set a formation.
|
|
if (count > 3)
|
|
ship_ai.squadSetFormationRandom(squad);
|
|
|
|
questCompleteTask(questCrc, taskId, player);
|
|
return;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
trigger OnTaskCompleted(int questCrc, int taskId)
|
|
{
|
|
cleanup(self, questCrc, taskId);
|
|
groundquests.questOutputDebugInfo(self, questCrc, taskId, taskType, "OnTaskCompleted", taskType + " task completed.");
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
trigger OnTaskFailed(int questCrc, int taskId)
|
|
{
|
|
cleanup(self, questCrc, taskId);
|
|
groundquests.questOutputDebugInfo(self, questCrc, taskId, taskType, "OnTaskFailed", taskType + " task failed.");
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
trigger OnTaskCleared(int questCrc, int taskId)
|
|
{
|
|
cleanup(self, questCrc, taskId);
|
|
groundquests.questOutputDebugInfo(self, questCrc, taskId, taskType, "OnTaskCleared", taskType + " task cleared.");
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
void cleanup(obj_id player, int questCrc, int taskId)
|
|
{
|
|
groundquests.clearBaseObjVar(player, taskType, questGetQuestName(questCrc), taskId);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
trigger OnDeath(obj_id killer, obj_id corpseId)
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
trigger OnLogout()
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
trigger OnDetach()
|
|
{
|
|
// make sure the base objvar is removed
|
|
removeObjVar(self, groundquests.getTaskTypeObjVar(self, taskType));
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
trigger OnInitialize()
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
|
|
// ================================================================================
|