Files
dsrc/sku.0/sys.server/compiled/game/script/library/storyteller.scriptlib
T
2013-09-10 23:17:15 -07:00

2212 lines
66 KiB
Plaintext

include library.ai_lib;
include library.city;
include library.beast_lib;
include library.instance;
include library.pet_lib;
include library.player_structure;
include library.space_utils;
include library.utils;
const string STORYTELLER_DATATABLE = "datatables/item/master_item/storyteller_item.iff";
const string STATIC_ITEM_DATATABLE = "datatables/item/master_item/master_item.iff";
const string THEATER_MODE = "theater_mode";
const string EFFECT_TOKEN_NAME = "storytellerEffectName";
const string EFFECT_ACTIVE_OBJVAR = "storytellerPersistedEffectActive";
const string STORYTELLER_THEATER_CONTROL_SCRIPT = "systems.storyteller.theater_controller";
const string STORYTELLER_PROP_CONTROL_SCRIPT = "systems.storyteller.prop_controller";
const string STORYTELLER_NPC_CONTROL_SCRIPT = "systems.storyteller.npc_controller";
const string STORYTELLER_DAILY_COUNT_OBJVAR = "storytellerToken.dailyCount";
const string STORYTELLER_DAILY_COUNT_RESET = "storytellerToken.dailyResetTime";
const string STORYTELLER_OBJECT_OBJVAR = "storytellerid";
const int BLUEPRINT_MAX_NUM_OBJECTS = 200;
const float BLUEPRINT_DEFAULT_RADIUS = 100.0f;
const string BLUEPRINT_OBJECTS_OBJVAR = "blueprintObjects";
const string BLUEPRINT_AUTHOR_OBJVAR = "blueprintAuthor";
const string BLUEPRINT_AUTHOR_NAME_OBJVAR = "blueprintAuthorName";
const string BLUEPRINT_DECRIPTION_OBJVAR = "blueprintDescription";
const int BLUEPRINT_CREATE_CYCLE_MAX = 30;
const int BLUEPRINT_CREATE_CYCLE_LOOP = 25;
const int BLUEPRINT_VERSION_NUM = 1;
const string BLUEPRINT_VERSION_OBJVAR = "blueprintVersion";
const int BLUEPRINT_TOKEN_LOADED = 1;
const int BLUEPRINT_TOKEN_NEEDED = 0;
const int PROP = 0;
const int STATIC_EFFECT = 1;
const int IMMEDIATE_EFFECT = 2;
const int COMBAT_NPC = 3;
const int FLAVOR_NPC = 4;
const int OTHER = 5;
const int COSTUME = 6;
const int THEATER = 7;
const int DEFAULT_PROP_CLEANUP_TIME = 16*60*60;//16 hours
const int DEFAULT_NPC_CLEANUP_TIME = 16*60*60;//16 hours
const string VAR_AUTODECLINE_STORY_INVITES = "decline_story_invites";
int getTokenType (obj_id token)
{
return dataTableGetInt(STORYTELLER_DATATABLE, getStaticItemName(token), "type");
}
int getTokenType (string tokenName)
{
return dataTableGetInt(STORYTELLER_DATATABLE, tokenName, "type");
}
boolean isProp(obj_id token)
{
return (dataTableGetInt(STORYTELLER_DATATABLE, getStaticItemName(token), "type") == PROP);
}
boolean isAnyNpc(obj_id token)
{
return (isFlavorNpc(token) || isCombatNpc(token));
}
boolean isFlavorNpc(obj_id token)
{
return (dataTableGetInt(STORYTELLER_DATATABLE, getStaticItemName(token), "type") == FLAVOR_NPC);
}
boolean isFlavorNpc(string tokenName)
{
return (dataTableGetInt(STORYTELLER_DATATABLE, tokenName, "type") == FLAVOR_NPC);
}
boolean isCombatNpc(obj_id token)
{
return (dataTableGetInt(STORYTELLER_DATATABLE, getStaticItemName(token), "type") == COMBAT_NPC);
}
boolean isAnyEffect(string st_effect_token)
{
return (isStaticEffect(st_effect_token) || isImmediateEffect(st_effect_token));
}
boolean isAnyEffect(obj_id token)
{
return (isStaticEffect(token) || isImmediateEffect(token));
}
boolean isStaticEffect(string st_effect_token)
{
return (dataTableGetInt(STORYTELLER_DATATABLE, st_effect_token, "type") == STATIC_EFFECT);
}
boolean isStaticEffect(obj_id token)
{
return (dataTableGetInt(STORYTELLER_DATATABLE, getStaticItemName(token), "type") == STATIC_EFFECT);
}
boolean isImmediateEffect(string st_effect_token)
{
return (dataTableGetInt(STORYTELLER_DATATABLE, st_effect_token, "type") == IMMEDIATE_EFFECT);
}
boolean isImmediateEffect(obj_id token)
{
return (dataTableGetInt(STORYTELLER_DATATABLE, getStaticItemName(token), "type") == IMMEDIATE_EFFECT);
}
boolean isTheater(obj_id token)
{
return (dataTableGetInt(STORYTELLER_DATATABLE, getStaticItemName(token), "type") == THEATER);
}
boolean isOther(obj_id token)
{
return (dataTableGetInt(STORYTELLER_DATATABLE, getStaticItemName(token), "type") == OTHER);
}
boolean isAnyStorytellerItem(obj_id token)
{
return (dataTableGetInt(STORYTELLER_DATATABLE, getStaticItemName(token), "type") != -1);
}
string getEffectName(string st_effect_name)
{
return dataTableGetString(STORYTELLER_DATATABLE, st_effect_name, "template_name");
}
string getNpcTemplate(obj_id token)
{
return dataTableGetString(STORYTELLER_DATATABLE, getStaticItemName(token), "template_name");
}
string getNpcTemplate(string tokenName)
{
return dataTableGetString(STORYTELLER_DATATABLE, tokenName, "template_name");
}
float getTheaterBuildoutRadius(obj_id theater)
{
return dataTableGetFloat(STORYTELLER_DATATABLE, getStaticItemName(theater), "buildout_radius");
}
obj_id createTheaterObject(obj_id token, boolean inBuildout)
{
obj_id player = getTopMostContainer(token);
if (!isPlayer(player))
return null;
float yaw = getYaw(player);
return createTheaterObject(token, inBuildout, getLocation(player), yaw);
}
obj_id createTheaterObject(obj_id token, boolean inBuildout, location createLoc, float yaw)
{
string itemName = getStaticItemName(token);
dictionary dict = new dictionary();
int row = dataTableSearchColumnForString( itemName , "name", storyteller.STORYTELLER_DATATABLE);
if (row == -1)
return null;
dict = dataTableGetRow(storyteller.STORYTELLER_DATATABLE, itemName);
string template = dict.getString("template_name");
string objVarString = dict.getString("objvar");
string scriptString = dict.getString("scripts");
obj_id theater = create.object(template, createLoc);
setYaw(theater, yaw);
if (!isIdValid(theater))
return null;
static_item.setObjVarString(theater, objVarString);
static_item.setScriptString(theater, scriptString);
setStaticItemName(theater, getStaticItemName(token));
setObjVar(theater, storyteller.THEATER_MODE, inBuildout);
attachScript(theater, STORYTELLER_THEATER_CONTROL_SCRIPT);
destroyObject(token);
return theater;
}
obj_id createPropObject(obj_id token, boolean inBuildout)
{
obj_id player = utils.getContainingPlayer(token);
if (!isIdValid(player))
return null;
float yaw = getYaw(player);
return createPropObject(token, player, inBuildout, getLocation(player), yaw);
}
obj_id createPropObject(obj_id token, obj_id player, boolean inBuildout, location createLoc, float yaw)
{
obj_id prop = null;
if ( canDeployStorytellerToken(player, createLoc, token) )
{
string itemName = getStaticItemName(token);
dictionary dict = new dictionary();
dictionary dict_m = new dictionary();
int row = dataTableSearchColumnForString( itemName , "name", STORYTELLER_DATATABLE);
if (row == -1)
return null;
dict = dataTableGetRow(STORYTELLER_DATATABLE, itemName);
string template = dict.getString("template_name");
string objVarString = dict.getString("objvar");
string scriptString = dict.getString("scripts");
dict_m = dataTableGetRow(STATIC_ITEM_DATATABLE, itemName);
string finalName = dict_m.getString("string_name");
prop = create.object(template, createLoc);
if ( isIdValid(prop) )
{
setYaw(prop, yaw);
setInvulnerable(prop, true);
static_item.setObjVarString(prop, objVarString);
static_item.setScriptString(prop, scriptString);
setStaticItemName(prop, getStaticItemName(token));
if ( utils.hasScriptVar(player, "storytellerAssistant") )
{
obj_id storytellerId = utils.getObjIdScriptVar(player, "storytellerAssistant");
string storytellerName = utils.getStringScriptVar(player, "storytellerAssistantName");
setObjVar(prop, "storytellerid", storytellerId);
setObjVar(prop, "storytellerName", storytellerName);
}
else
{
setObjVar(prop, "storytellerid", player);
setObjVar(prop, "storytellerName", getName(player));
}
setObjVar(prop, "storytellerCreationLoc", createLoc);
setObjVar(prop, "storytellerTokenName", itemName);
attachScript(prop, STORYTELLER_PROP_CONTROL_SCRIPT);
setName(prop, finalName);
handleTokenUsage(token);
string logMsg = "("+player+")"+getName(player)+" is deploying a prop storyteller token: "+getStaticItemName(token)+" at "+createLoc;
CustomerServiceLog("storyteller", logMsg);
}
}
return prop;
}
obj_id createPropObjectNoToken(string tokenName, obj_id player, boolean inBuildout, location createLoc, float yaw)
{
obj_id prop = null;
if ( canDeployStorytellerToken(player, createLoc, tokenName) )
{
dictionary dict = new dictionary();
dictionary dict_m = new dictionary();
int row = dataTableSearchColumnForString( tokenName , "name", STORYTELLER_DATATABLE);
if (row == -1)
return null;
dict = dataTableGetRow(STORYTELLER_DATATABLE, tokenName);
string template = dict.getString("template_name");
string objVarString = dict.getString("objvar");
string scriptString = dict.getString("scripts");
dict_m = dataTableGetRow(STATIC_ITEM_DATATABLE, tokenName);
string finalName = dict_m.getString("string_name");
prop = create.object(template, createLoc);
if ( isIdValid(prop) )
{
setYaw(prop, yaw);
setInvulnerable(prop, true);
static_item.setObjVarString(prop, objVarString);
static_item.setScriptString(prop, scriptString);
setStaticItemName(prop, tokenName);
if ( utils.hasScriptVar(player, "storytellerAssistant") )
{
obj_id storytellerId = utils.getObjIdScriptVar(player, "storytellerAssistant");
string storytellerName = utils.getStringScriptVar(player, "storytellerAssistantName");
setObjVar(prop, "storytellerid", storytellerId);
setObjVar(prop, "storytellerName", storytellerName);
}
else
{
setObjVar(prop, "storytellerid", player);
setObjVar(prop, "storytellerName", getName(player));
}
setObjVar(prop, "storytellerCreationLoc", createLoc);
setObjVar(prop, "storytellerTokenName", tokenName);
attachScript(prop, STORYTELLER_PROP_CONTROL_SCRIPT);
setName(prop, finalName);
string logMsg = "("+player+")"+getName(player)+" is deploying a prop storyteller token: "+tokenName+" at "+createLoc;
CustomerServiceLog("storyteller", logMsg);
}
}
return prop;
}
obj_id createNpcAtLocation(obj_id token)
{
obj_id player = utils.getContainingPlayer(token);
float yaw = getYaw(player);
return createNpcAtLocation(token, player, getLocation(player), yaw);
}
obj_id createNpcAtLocation(obj_id token, obj_id player, location createLoc, float yaw)
{
obj_id npc = null;
if ( canDeployStorytellerToken(player, createLoc, token) )
{
string toCreate = storyteller.getNpcTemplate(token);
npc = create.object(toCreate, createLoc);
if ( isIdValid(npc) )
{
if ( utils.hasScriptVar(player, "storytellerAssistant") )
{
obj_id storytellerId = utils.getObjIdScriptVar(player, "storytellerAssistant");
string storytellerName = utils.getStringScriptVar(player, "storytellerAssistantName");
setObjVar(npc, "storytellerid", storytellerId);
setObjVar(npc, "storytellerName", storytellerName);
}
else
{
setObjVar(npc, "storytellerid", player);
setObjVar(npc, "storytellerName", getName(player));
}
setObjVar(npc, "storytellerCreationLoc", createLoc);
setObjVar(npc, "storytellerTokenName", getStaticItemName(token));
setYaw(npc, yaw);
setStaticItemName(npc, getStaticItemName(token));
if (storyteller.isFlavorNpc(token))
setInvulnerable(npc, true);
ai_lib.setDefaultCalmBehavior(npc, ai_lib.BEHAVIOR_SENTINEL);
if ( hasObjVar(token, "storytellerNpcCombatLevel") )
{
int storytellerNpcCombatLevel = getIntObjVar(token, "storytellerNpcCombatLevel");
if (storytellerNpcCombatLevel < 1 || storytellerNpcCombatLevel > 90)
{
storytellerNpcCombatLevel = 1;
}
dictionary creatureDict = utils.dataTableGetRow(create.CREATURE_TABLE, toCreate);
if ( creatureDict != null )
{
create.initializeCreature(npc, toCreate, creatureDict, storytellerNpcCombatLevel);
}
}
attachScript(npc, STORYTELLER_NPC_CONTROL_SCRIPT);
string logMsg = "("+player+")"+getName(player)+" is deploying an npc storyteller token: "+getStaticItemName(token)+" at "+createLoc;
CustomerServiceLog("storyteller", logMsg);
}
}
return npc;
}
obj_id createNpcAtLocationNoToken(string tokenName, obj_id player, location createLoc, float yaw)
{
return createNpcAtLocationNoToken(tokenName, player, createLoc, yaw, 0);
}
obj_id createNpcAtLocationNoToken(string tokenName, obj_id player, location createLoc, float yaw, int combatLevel)
{
return createNpcAtLocationNoToken(tokenName, player, createLoc, yaw, combatLevel, 0);
}
obj_id createNpcAtLocationNoToken(string tokenName, obj_id player, location createLoc, float yaw, int combatLevel, int difficulty)
{ obj_id npc = null;
if ( canDeployStorytellerToken(player, createLoc, tokenName) )
{
string toCreate = storyteller.getNpcTemplate(tokenName);
npc = create.object(toCreate, createLoc);
if ( isIdValid(npc) )
{
if ( utils.hasScriptVar(player, "storytellerAssistant") )
{
obj_id storytellerId = utils.getObjIdScriptVar(player, "storytellerAssistant");
string storytellerName = utils.getStringScriptVar(player, "storytellerAssistantName");
setObjVar(npc, "storytellerid", storytellerId);
setObjVar(npc, "storytellerName", storytellerName);
}
else
{
setObjVar(npc, "storytellerid", player);
setObjVar(npc, "storytellerName", getName(player));
}
setObjVar(npc, "storytellerCreationLoc", createLoc);
setObjVar(npc, "storytellerTokenName", tokenName);
setYaw(npc, yaw);
setStaticItemName(npc, tokenName);
if (storyteller.isFlavorNpc(tokenName))
setInvulnerable(npc, true);
ai_lib.setDefaultCalmBehavior(npc, ai_lib.BEHAVIOR_SENTINEL);
if ( combatLevel > 0 )
{
if ( combatLevel > 90)
combatLevel = 90;
dictionary creatureDict = utils.dataTableGetRow(create.CREATURE_TABLE, toCreate);
if ( creatureDict != null )
{
creatureDict.put("difficultyClass", difficulty);
create.initializeCreature(npc, toCreate, creatureDict, combatLevel);
setNpcDifficulty(npc, difficulty);
}
}
attachScript(npc, STORYTELLER_NPC_CONTROL_SCRIPT);
string logMsg = "("+player+")"+getName(player)+" is deploying an npc storyteller token: "+tokenName+" at "+createLoc;
CustomerServiceLog("storyteller", logMsg);
}
}
return npc;
}
boolean isStorytellerNpc(obj_id npc)
{
return hasObjVar(npc, "storytellerid");
}
boolean isStorytellerObject(obj_id object)
{
return hasObjVar(object, "storytellerid");
}
void removeStorytellerPersistedEffect(obj_id self)
{
obj_id[] players = getPlayerCreaturesInRange(getLocation(self), 165.0f);
if (players != null || players.length > 0)
{
stopClientEffectObjByLabel(players, self, "storyteller_persisted_effect", false);
removeObjVar(self, storyteller.EFFECT_ACTIVE_OBJVAR);
removeTriggerVolume("storytellerPersistedEffect");
}
return;
}
boolean allowTokenPlacementInInteriors(obj_id token)
{
return allowTokenPlacementInInteriors(getStaticItemName(token));
}
boolean allowTokenPlacementInInteriors(string tokenName)
{
int allowInInteriors = dataTableGetInt(STORYTELLER_DATATABLE, tokenName, "allow_interior");
return allowInInteriors == 1;
}
obj_id getStorytellerBeingAssisted(obj_id player)
{
obj_id storytellerBeingAssisted = null;
if ( utils.hasScriptVar(player, "storytellerAssistant"))
{
storytellerBeingAssisted = utils.getObjIdScriptVar(player, "storytellerAssistant");
}
return storytellerBeingAssisted;
}
location rotateLocationXZ(location locOrigin, location locPoint, float fltAngle)
{
float dx = locPoint.x - locOrigin.x;
float dz = locPoint.z - locOrigin.z;
float fltRadians = (float)Math.toRadians(fltAngle);
float fltC = (float)Math.cos(fltRadians);
float fltS = (float) Math.sin(fltRadians);
location locNewOffset = locOrigin;
locNewOffset.x += (dx * fltC) + (dz * fltS);
locNewOffset.y = locPoint.y;
locNewOffset.z += -(dx * fltS) + (dz * fltC);
return locNewOffset;
}
//***********************************************************************
// Daily Usage (daily_uses column in storyteller_item.tab)
// if -1, the token may be used without limit (this is pretty much just for event team tokens)
// if 0, the token expends charges and is destroyed when all uses are expended
// if > 0, the token is never destroyed, but has a limited number of uses per day as defined by daily_uses
int getTokenDailyUsageAmount(obj_id token)
{
return getTokenDailyUsageAmount(getStaticItemName(token));
}
int getTokenDailyUsageAmount(string tokenName)
{
return dataTableGetInt(STORYTELLER_DATATABLE, tokenName, "daily_uses");
}
boolean isTokenFlaggedWithDailyUsage(obj_id token)
{
return isTokenFlaggedWithDailyUsage(getStaticItemName(token));
}
boolean isTokenFlaggedWithDailyUsage(string tokenName)
{
int dailyUses = getTokenDailyUsageAmount(tokenName);
if ( dailyUses > 0 )
{
return true;
}
return false;
}
int getTokenDailyUsesAvailable(obj_id token)
{
int num = 0;
if ( isTokenFlaggedWithDailyUsage(getStaticItemName(token)) )
{
int dailyUses = getTokenDailyUsageAmount(token);
if ( dailyUses < 0 )
{
num = 9999;
}
else if ( hasObjVar(token, STORYTELLER_DAILY_COUNT_OBJVAR) )
{
int usedUses = getIntObjVar(token, STORYTELLER_DAILY_COUNT_OBJVAR);
num = dailyUses - usedUses;
}
else
{
num = dailyUses;
}
}
return num;
}
boolean hasTokenUsesAvailable(obj_id token)
{
int num = 0;
if ( isTokenFlaggedWithDailyUsage(getStaticItemName(token)) )
{
num = getTokenDailyUsesAvailable(token);
if ( num > 0 )
{
return true;
}
}
else
{
return true;
}
return false;
}
void handleTokenUsage(obj_id token)
{
int dailyUses = getTokenDailyUsageAmount(token);
if ( dailyUses == 0 )
{
decrementCount(token);
}
else if ( dailyUses > 0 )
{
int dailyCount = 1;
if ( hasObjVar(token, STORYTELLER_DAILY_COUNT_OBJVAR) )
{
dailyCount = getIntObjVar(token, STORYTELLER_DAILY_COUNT_OBJVAR) + 1;
}
setObjVar(token, STORYTELLER_DAILY_COUNT_OBJVAR, dailyCount);
sendDirtyAttributesNotification(token);
}
return;
}
void resetTokenDailyCount(obj_id token)
{
if ( isTokenFlaggedWithDailyUsage(token) )
{
if ( !hasObjVar(token, storyteller.STORYTELLER_DAILY_COUNT_RESET) )
{
setTokenDailyCountResetTime(token);
}
else
{
int currentTime = getCalendarTime();
int alarmTime = getIntObjVar(token, storyteller.STORYTELLER_DAILY_COUNT_RESET);
if ( currentTime >= alarmTime )
{
setTokenDailyCountResetTime(token);
if ( hasObjVar(token, STORYTELLER_DAILY_COUNT_OBJVAR) )
{
removeObjVar(token, STORYTELLER_DAILY_COUNT_OBJVAR);
}
}
}
}
return;
}
void setTokenDailyCountResetTime(obj_id token)
{
int currentTime = getCalendarTime();
int timeUntilAlarm = createDailyAlarmClock(token, "storytellerEffectTokenDailyAlarm", null, 4, 0, 0);
int alarmStamp = currentTime + timeUntilAlarm;
setObjVar(token, storyteller.STORYTELLER_DAILY_COUNT_RESET, alarmStamp);
return;
}
//***********************************************************************
boolean canDeployStorytellerToken(obj_id player, location here, obj_id token)
{
if ( !storyteller.hasTokenUsesAvailable(token) )
{
sendSystemMessage(player, new string_id("storyteller", "placement_daily_uses_expended"));
return false;
}
return canDeployStorytellerToken(player, here, getStaticItemName(token));
}
boolean canDeployStorytellerToken(obj_id player, location here, string tokenName)
{
if( !isIdValid(player) || here == null )
{
return false;
}
// God mode override to allow event team to place storyteller items with more freedom
if ( isGod(player) )
{
string logMsg = "("+player+")"+getName(player)+" is using GodMode override to deploy or movea storyteller object: "+tokenName+" at "+here;
CustomerServiceLog("storyteller", logMsg);
if ( !utils.hasScriptVar(player, "storyteller.godModeStopOverrideMessages") )
{
sendSystemMessage(player, new string_id("storyteller", "placement_god_mode"));
}
return true;
}
if( isFreeTrialAccount(player) )
{
sendSystemMessage(player, new string_id("storyteller", "placement_no_trial_accounts"));
return false;
}
obj_id myCell = here.cell;
obj_id myContainer = getTopMostContainer(myCell);
obj_id storytellerBeingAssisted = getStorytellerBeingAssisted(player);
if ( !isIdValid(storytellerBeingAssisted) )
{
storytellerBeingAssisted = player;
}
// At this point in time, storyteller objects are not allowed in any instances.
if ( instance.isInInstanceArea(player) )
{
sendSystemMessage(player, new string_id("storyteller", "placement_not_in_this_location"));
return false;
}
// *************************************************
// SPACE
// block all storyteller object placement in space
// unless the object is flagged as allowed in interiors and is in a player pob ship
string planet = here.area;
if( planet.startsWith("space_") )
{
if ( isIdValid(myCell) && allowTokenPlacementInInteriors(tokenName) )
{
obj_id owner= getOwner(myContainer);
if ( !isIdValid(owner) || owner != player || owner != storytellerBeingAssisted )
{
sendSystemMessage(player, new string_id("storyteller", "placement_not_ship_owner"));
return false;
}
if ( getState(player, STATE_SHIP_INTERIOR) != 1 || space_utils.isInStation(player) )
{
sendSystemMessage(player, new string_id("storyteller", "placement_not_in_station"));
return false;
}
}
else
{
sendSystemMessage(player, new string_id("storyteller", "placement_not_in_space"));
return false;
}
}
// *************************************************
else
{
// *************************************************
// INTERIORS - inside of a pob
// block storyteller object placement inside of buildings
// unless the object is flagged as allowed in interiors
if( isIdValid(myCell) )
{
if ( !allowTokenPlacementInInteriors(tokenName) )
{
sendSystemMessage(player, new string_id("storyteller", "placement_not_in_a_building"));
return false;
}
else
{
if ( !player_structure.isAdmin(myContainer, player) && !player_structure.isAdmin(myContainer, storytellerBeingAssisted) )
{
sendSystemMessage(player, new string_id("storyteller", "placement_not_building_admin"));
return false;
}
}
}
// *************************************************
// Not inside of a building
else
{
// block storyteller object placement on adventure planets
if ( planet.equals("mustafar") || planet.startsWith("kashyyyk") )
{
sendSystemMessage(player, new string_id("storyteller", "placement_not_on_blocked_planet"));
return false;
}
// block storyteller object placement in nobuild regions
region[] rgnTest = getRegionsWithBuildableAtPoint(here, regions.BUILD_FALSE );
if ( rgnTest != null )
{
// There are regions at this location with buildable set to true.
sendSystemMessage(player, new string_id("storyteller", "placement_not_in_municipal_zone"));
return false;
}
// block storyteller object placement in storyteller blocking regions
// (any regions with "storytellerblocked" in its name)
if ( isInStorytellerBlockedRegion(here) )
{
sendSystemMessage(player, new string_id("storyteller", "placement_not_in_this_location"));
return false;
}
// block storyteller object placement on player structure roofs and balconies
// unless the object is flagged as allowed in interiors
obj_id whatAmIStandingOn = getStandingOn(player);
if( isIdValid(whatAmIStandingOn) && player_structure.isBuilding(whatAmIStandingOn) )
{
sendSystemMessage(player, new string_id("storyteller", "placement_not_on_a_building"));
return false;
}
// city or outpost
// if you are inside of a cell, permission checks have already been made.
if( locations.isInMissionCity(here) )
{
int city_id = getCityAtLocation(here, 0);
// It's an NPC city
if(city_id == 0)
{
sendSystemMessage(player, new string_id("storyteller", "placement_not_in_municipal_zone"));
return false;
}
// Zoning rights for player city
if ( cityExists(city_id) && city.isCityZoned(city_id) && isIdValid(player))
{
if(!city.hasStorytellerZoningRights(player, city_id))
{
sendSystemMessage(player, new string_id("storyteller", "placement_no_zoning_rights"));
return false;
}
}
}
}
}
return true;
}
boolean isInStorytellerBlockedRegion(location here)
{
region[] regionsHere = getRegionsAtPoint(here);
if ( regionsHere != null && regionsHere.length > 0 )
{
for ( int i = 0; i < regionsHere.length; i++ )
{
region testRegion = regionsHere[i];
string regionName = testRegion.getName();
int nameCheck = regionName.indexOf("storytellerblocked");
if ( nameCheck > -1 )
{
return true;
}
}
}
return false;
}
boolean allowedToSeeStorytellerObject(obj_id object, obj_id player)
{
obj_id storyteller = getObjIdObjVar(object, "storytellerid");
if ( isIdValid(storyteller) )
{
if (allowedToUseStorytellerObject(object, player) )
{
return true;
}
if ( utils.hasScriptVar(player, "storytellerid") )
{
obj_id playersStoryteller = utils.getObjIdScriptVar(player, "storytellerid");
if ( isIdValid(playersStoryteller) && storyteller == playersStoryteller )
{
return true;
}
}
}
return false;
}
boolean allowedToUseStorytellerObject(obj_id object, obj_id player)
{
obj_id storyteller = getObjIdObjVar(object, "storytellerid");
if ( isIdValid(storyteller) )
{
if ( storyteller == player )
{
return true;
}
else if ( utils.hasScriptVar(player, "storytellerAssistant") )
{
obj_id whoAmIAssisting = utils.getObjIdScriptVar(player, "storytellerAssistant");
if ( isIdValid(whoAmIAssisting) && storyteller == whoAmIAssisting )
{
return true;
}
}
}
return false;
}
boolean inSameStory(obj_id target1, obj_id target2)
{
obj_id storyteller_id_1 = obj_id.NULL_ID;
obj_id storyteller_id_2 = obj_id.NULL_ID;
if ( utils.hasScriptVar(target1, "storytellerid") )
{
storyteller_id_1 = utils.getObjIdScriptVar(target1, "storytellerid");
}
if ( utils.hasScriptVar(target2, "storytellerid") )
{
storyteller_id_2 = utils.getObjIdScriptVar(target2, "storytellerid");
}
// if the storyteller_id of both players is the same, they are in the same story
//
// OR if the storyteller_id of one player is equal to the obj_id of the other player,
// then that player is in the other player's story
if ( isIdValid(storyteller_id_1) && isIdValid(storyteller_id_2) )
{
if ( storyteller_id_1 == storyteller_id_2 )
{
return true;
}
}
else if ( isIdValid(storyteller_id_1) && storyteller_id_1 == target2 )
{
return true;
}
else if ( isIdValid(storyteller_id_2) && storyteller_id_2 == target1 )
{
return true;
}
return false;
}
void showStorytellerEffectsInAreaToPlayer(obj_id player, obj_id storytellerPlayer)
{
obj_id[] storytellerObjects = getAllObjectsWithObjVar(getLocation(player), 165.0f, "storytellerid");
if ( storytellerObjects != null && storytellerObjects.length > 0 )
{
for ( int i = 0; i < storytellerObjects.length; i++ )
{
obj_id object = storytellerObjects[i];
obj_id myStoryteller = getObjIdObjVar(object, "storytellerid");
if ( isIdValid(myStoryteller) )
{
if ( myStoryteller == storytellerPlayer )
{
if ( hasObjVar(object, storyteller.EFFECT_ACTIVE_OBJVAR) && hasObjVar(object, storyteller.EFFECT_TOKEN_NAME) )
{
string storytellerTokenName = getStringObjVar(object, storyteller.EFFECT_TOKEN_NAME);
location here = getLocation(object);
string effectName = storyteller.getEffectName(storytellerTokenName);
obj_id[] playerInStory = { player };
playClientEffectObj(playerInStory, effectName, object, "", null, "storyteller_persisted_effect");
}
}
}
}
}
return;
}
void stopStorytellerEffectsInAreaToPlayer(obj_id player, obj_id storytellerPlayer)
{
obj_id[] storytellerObjects = getAllObjectsWithObjVar(getLocation(player), 165.0f, "storytellerid");
if ( storytellerObjects != null && storytellerObjects.length > 0 )
{
for ( int i = 0; i < storytellerObjects.length; i++ )
{
obj_id object = storytellerObjects[i];
obj_id myStoryteller = getObjIdObjVar(object, "storytellerid");
if ( isIdValid(myStoryteller) )
{
if ( myStoryteller == storytellerPlayer )
{
if ( hasObjVar(object, storyteller.EFFECT_ACTIVE_OBJVAR) && hasObjVar(object, storyteller.EFFECT_TOKEN_NAME) )
{
string storytellerTokenName = getStringObjVar(object, storyteller.EFFECT_TOKEN_NAME);
location here = getLocation(object);
string effectName = storyteller.getEffectName(storytellerTokenName);
stopClientEffectObjByLabel(player, object, "storyteller_persisted_effect", false);
}
}
}
}
}
return;
}
/***************************************************************************/
// Storyteller Blueprint functions
string[] recordBlueprintData(obj_id blueprint, obj_id[] storytellerObjects, obj_id player)
{
resizeable string[] blueprintString = new string[0];
// Find storyteller objects that belong to the player and are valid to be saved in their blueprint
resizeable obj_id[] validStorytellerObjects = new obj_id[0];
for ( int i=0; i < storytellerObjects.length; i++ )
{
obj_id object = storytellerObjects[i];
obj_id objectOwner = getObjIdObjVar(object, "storytellerid");
if ( !isIdValid(objectOwner) || objectOwner != player )
{
continue;
}
if ( hasObjVar(object, storyteller.BLUEPRINT_AUTHOR_OBJVAR) )
{
obj_id blueprintAuthor = getObjIdObjVar(object, storyteller.BLUEPRINT_AUTHOR_OBJVAR);
if ( !isIdValid( blueprintAuthor ) || blueprintAuthor != player )
{
continue;
}
}
string tokenName = getStaticItemName(object);
if ( tokenName == null || tokenName.length() < 1 )
{
continue;
}
string[] excludedTokens = { "st_fn_storyteller_vendor" };
boolean isExcludedToken = false;
for ( int q=0; q<excludedTokens.length; q++ )
{
if ( tokenName.equals(excludedTokens[q]) || storyteller.getTokenType(tokenName) == storyteller.OTHER )
{
isExcludedToken = true;
}
}
if ( isExcludedToken )
{
continue;
}
utils.addElement(validStorytellerObjects, object);
}
if ( validStorytellerObjects == null || validStorytellerObjects.length < 1 )
{
return blueprintString;
}
// Find the center location of the valid objects to use as a reference point for thier position
location centerLoc = new location();
float maxX = -99999.0f;
float maxZ = -99999.0f;
float minX = 99999.0f;
float minZ = 99999.0f;
for ( int j=0; j < validStorytellerObjects.length; j++ )
{
obj_id object = validStorytellerObjects[j];
obj_id objectOwner = getObjIdObjVar(object, "storytellerid");
if ( !isIdValid(objectOwner) || objectOwner != player )
{
continue;
}
location objLoc = getLocation(object);
if ( objLoc.x > maxX )
maxX = objLoc.x;
if ( objLoc.z > maxZ )
maxZ = objLoc.z;
if ( objLoc.x < minX )
minX = objLoc.x;
if ( objLoc.z < minZ )
minZ = objLoc.z;
}
centerLoc = new location(maxX - ((maxX - minX)/2), 0.0f, maxZ - ((maxZ - minZ)/2));
// Find the relative position of each valid object
for ( int i=0; i < validStorytellerObjects.length; i++ )
{
obj_id validStoryObject = validStorytellerObjects[i];
string tokenName = getStaticItemName(validStoryObject);
location playerLoc = getLocation(player);
float playerYaw = getYaw(player);
location objLoc = getLocation(validStoryObject);
float objYaw = getYaw(validStoryObject);
if ( playerYaw != 0 )
{
objLoc = storyteller.rotateSavedBlueprintDataXZ(playerLoc, objLoc, playerYaw);
}
float yawDiff = playerYaw - objYaw;
float terrainHeight = objLoc.y;
location creationLoc = getLocationObjVar(validStoryObject, "storytellerCreationLoc");
if ( creationLoc != null )
{
terrainHeight = creationLoc.y;
}
float locX = objLoc.x - playerLoc.x;
float locY = objLoc.y - terrainHeight;
float locZ = objLoc.z - playerLoc.z;
// locY should never have a negative value. Storyteller objects cannot be moved below the terrain.
// So the only reason it would be negative is if both getElevation() and getHeightAtLocation() failed.
if ( locY < 0.001f )
{
locY = 0.0f;
}
int combatLevel = 0;
int difficulty = 0;
if ( isMob(validStoryObject) )
{
combatLevel = getLevel(validStoryObject);
difficulty = getIntObjVar(validStoryObject, "difficultyClass");
}
string effect = "none";
if ( hasObjVar(validStoryObject, storyteller.EFFECT_ACTIVE_OBJVAR) && hasObjVar(validStoryObject, storyteller.EFFECT_TOKEN_NAME) )
{
effect = getStringObjVar(validStoryObject, storyteller.EFFECT_TOKEN_NAME);
// The effect token is saved in reference to the object it plays on.
// This entry is simply to track that an effect token is required and has/hasn't been loaded.
string effectEntry = buildBlueprintObjectData(storyteller.BLUEPRINT_TOKEN_NEEDED, effect, 0.0f, 0.0f, 0.0f, 0.0f, 0, 0, "none");
utils.addElement(blueprintString, effectEntry);
}
string newEntry = buildBlueprintObjectData(storyteller.BLUEPRINT_TOKEN_NEEDED, tokenName, locX, locY, locZ, yawDiff, combatLevel, difficulty, effect);
utils.addElement(blueprintString, newEntry);
if ( blueprintString.length >= BLUEPRINT_MAX_NUM_OBJECTS )
{
break;
}
}
return blueprintString;
}
location rotateSavedBlueprintDataXZ(location locOrigin, location locPoint, float fltAngle)
{
float dx = locPoint.x - locOrigin.x;
float dz = locPoint.z - locOrigin.z;
float fltRadians = (float)Math.toRadians(fltAngle);
float fltC = (float)Math.cos(fltRadians);
float fltS = (float) Math.sin(fltRadians);
location locNewOffset = locOrigin;
locNewOffset.x += -(dx * fltC) + (dz * fltS);
locNewOffset.y = locPoint.y;
locNewOffset.z += (dx * fltS) + (dz * fltC);
return locNewOffset;
}
string changeBlueprintItemTokenStatus(int tokenStatus, string objectData)
{
return buildBlueprintObjectData(tokenStatus, getBlueprintItemName(objectData), getBlueprintItemLocX(objectData), getBlueprintItemLocY(objectData), getBlueprintItemLocZ(objectData), getBlueprintItemYaw(objectData), getBlueprintItemCombatLevel(objectData), getBlueprintItemDifficulty(objectData), getBlueprintItemEffect(objectData));
}
string buildBlueprintObjectData(int tokenLoaded, string tokenName, float locX, float locY, float locZ, float yaw, int combatLevel, int difficulty, string effect)
{
return tokenLoaded+"~"+tokenName+"~"+locX+"~"+locY+"~"+locZ+"~"+yaw+"~"+combatLevel+"~"+difficulty+"~"+effect;
}
int getBlueprintObjectDataSize(string blueprintObjectData)
{
string[] parse = split(blueprintObjectData, '~');
return parse.length;
}
int getRequiredBlueprintDataSize()
{
string blueprintDataTest = buildBlueprintObjectData(BLUEPRINT_TOKEN_NEEDED, "test_only", 0.0f,0.0f, 0.0f, 0.0f, 0, 0, "none");
return getBlueprintObjectDataSize(blueprintDataTest);
}
boolean validateBlueprintData(string blueprintObjectData)
{
if ( getBlueprintObjectDataSize(blueprintObjectData) == getRequiredBlueprintDataSize() )
{
return true;
}
return false;
}
obj_id createBlueprintObject(string objectData, obj_id blueprintController, obj_id player, location targetLoc, float targetYaw)
{
obj_id blueprintObject = obj_id.NULL_ID;
string tokenName = getBlueprintItemName(objectData);
location atLoc = getBlueprintObjectLocation(objectData, targetLoc);
float yawDiff = getBlueprintItemYaw(objectData);
int combatLevel = getBlueprintItemCombatLevel(objectData);
int difficulty = getBlueprintItemDifficulty(objectData);
string effect = getBlueprintItemEffect(objectData);
if ( targetYaw != 0 )
{
atLoc = storyteller.rotateSavedBlueprintDataXZ(targetLoc, atLoc, targetYaw);
}
float newYaw = targetYaw - yawDiff;
int tokenType = storyteller.getTokenType(tokenName);
switch(tokenType)
{
case storyteller.PROP:
blueprintObject = storyteller.createPropObjectNoToken(tokenName, player, false, atLoc, newYaw);
break;
case storyteller.COMBAT_NPC:
blueprintObject = storyteller.createNpcAtLocationNoToken(tokenName, player, atLoc, newYaw, combatLevel, difficulty);
break;
case storyteller.FLAVOR_NPC:
blueprintObject = storyteller.createNpcAtLocationNoToken(tokenName, player, atLoc, newYaw, combatLevel, difficulty);
break;
case storyteller.STATIC_EFFECT:
// The effect token is saved in reference to the object it plays on.
// This entry is simply to track that an effect token is required and has/hasn't been loaded.
break;
}
if ( isValidId(blueprintObject) )
{
// save obj_id of the blueprint author
if ( hasObjVar(blueprintController, storyteller.BLUEPRINT_AUTHOR_OBJVAR) )
{
obj_id blueprintAuthor = getObjIdObjVar(blueprintController, storyteller.BLUEPRINT_AUTHOR_OBJVAR);
if ( isIdValid(blueprintAuthor) )
{
setObjVar(blueprintObject, storyteller.BLUEPRINT_AUTHOR_OBJVAR, blueprintAuthor);
}
}
// if a persisted effect is being used on the object, play it
if ( effect.length() > 0 && !effect.equals("none") )
{
setObjVar(blueprintObject, storyteller.EFFECT_TOKEN_NAME, effect);
if ( hasScript(blueprintObject, "systems.storyteller.effect_controller") )
{
messageTo(blueprintObject, "handlePlayNewStorytellerEffect", null, 1, false);
}
else
{
attachScript(blueprintObject, "systems.storyteller.effect_controller");
}
}
dictionary webster = new dictionary();
webster.put("yOffset", getBlueprintItemLocY(objectData));
webster.put("player", player);
messageTo(blueprintObject, "handleBlueprintElevation", webster, 0.25f, false);
}
if ( isGod(player) )
{
utils.setScriptVar(player, "storyteller.godModeStopOverrideMessages", true);
}
return blueprintObject;
}
void handleBlueprintObjectElevation(obj_id blueprintObject, dictionary params)
{
if ( params != null || !params.isEmpty() )
{
float yOffset = params.getFloat("yOffset");
obj_id player = params.getObjId("player");
location here = getLocation(blueprintObject);
setObjVar(blueprintObject, "storytellerCreationLoc", here);
location newElevationLoc = new location(here.x, here.y + yOffset, here.z);
setLocation(blueprintObject, newElevationLoc);
}
return;
}
location getBlueprintObjectLocation(string spawnString, location centerLoc)
{
float locX = centerLoc.x + getBlueprintItemLocX(spawnString);
float locZ = centerLoc.z + getBlueprintItemLocZ(spawnString);
// sending an incorrect elevation at this point. It will be corrected later during the creation process.
float locY = centerLoc.y;
return new location(locX, locY, locZ, centerLoc.area, null);
}
boolean isBlueprintTokenLoaded(string spawnString)
{
string[] parse = split(spawnString, '~');
if ( utils.stringToInt(parse[0]) == 1 )
return true;
return false;
}
string getBlueprintItemName(string spawnString)
{
string[] parse = split(spawnString, '~');
return parse[1];
}
float getBlueprintItemLocX(string spawnString)
{
string[] parse = split(spawnString, '~');
return utils.stringToFloat(parse[2]);
}
float getBlueprintItemLocY(string spawnString)
{
string[] parse = split(spawnString, '~');
return utils.stringToFloat(parse[3]);
}
float getBlueprintItemLocZ(string spawnString)
{
string[] parse = split(spawnString, '~');
return utils.stringToFloat(parse[4]);
}
float getBlueprintItemYaw(string spawnString)
{
string[] parse = split(spawnString, '~');
return utils.stringToFloat(parse[5]);
}
int getBlueprintItemCombatLevel(string spawnString)
{
string[] parse = split(spawnString, '~');
return utils.stringToInt(parse[6]);
}
int getBlueprintItemDifficulty(string spawnString)
{
string[] parse = split(spawnString, '~');
return utils.stringToInt(parse[7]);
}
string getBlueprintItemEffect(string spawnString)
{
string[] parse = split(spawnString, '~');
return parse[8];
}
void blueprintParseConversion(obj_id blueprint)
{
// CTS uses | when packing objvars, so blueprint data cannot use | when recording
// blueprint object data in its data objvar. This function will convert previously existing blueprints
// away from splitting their data with | and reset their data to use ~
string[] blueprintObjects = utils.getStringBatchObjVar(blueprint, storyteller.BLUEPRINT_OBJECTS_OBJVAR);
if ( blueprintObjects == null || blueprintObjects.length == 0 )
{
// no blueprint found so no need to convert it.
return;
}
boolean conversionWasRequired = false;
for (int i=0; i < blueprintObjects.length; i++)
{
string objectData = blueprintObjects[i];
string[] oldParse = split(objectData, '|');
if ( oldParse.length > 1 )
{
int tokenLoaded = utils.stringToInt(oldParse[0]);
string tokenName = oldParse[1];
float locX = utils.stringToFloat(oldParse[2]);
float locY = utils.stringToFloat(oldParse[3]);
float locZ = utils.stringToFloat(oldParse[4]);
float yaw = utils.stringToFloat(oldParse[5]);
int combatLevel = utils.stringToInt(oldParse[6]);
int difficulty = utils.stringToInt(oldParse[7]);
string effect = oldParse[8];
string convertedObjectData = buildBlueprintObjectData(tokenLoaded, tokenName, locX, locY, locZ, yaw, combatLevel, difficulty, effect);
blueprintObjects[i] = convertedObjectData;
conversionWasRequired = true;
}
}
if ( conversionWasRequired )
{
utils.setBatchObjVar(blueprint, storyteller.BLUEPRINT_OBJECTS_OBJVAR, blueprintObjects);
}
return;
}
/***************************************************************************/
// Auto-decline Storyteller Invites
boolean doIAutoDeclineStorytellerInvites(obj_id player)
{
// is auto-declining all storyteller invites
if ( hasObjVar(player, storyteller.VAR_AUTODECLINE_STORY_INVITES) )
{
return true;
}
// is in a battlefield
if ( utils.hasScriptVar(player, "battlefield.active") )
{
return true;
}
return false;
}
// Storyteller Assistant Invite
int storyAssistantSui(obj_id storytellerPlayer, string storytellerName, obj_id player)
{
string title = utils.packStringId(new string_id("storyteller", "assistant_title"));
prose_package pp = prose.getPackage(new string_id("storyteller", "assistant_invite"));
prose.setTO(pp, storytellerName);
string msg = "\0" + packOutOfBandProsePackage(null, pp);
int pid = sui.msgbox(storytellerPlayer, player, msg, 2, title, sui.YES_NO, "storyAssistantHandler");
return pid;
}
void storyAssistantAcepted(obj_id storytellerPlayer, string storytellerName, obj_id player)
{
string_id message = new string_id ("storyteller", "assistant_player_name");
prose_package pp = prose.getPackage(message, player, player);
prose.setTO(pp, storytellerName);
sendSystemMessageProse(player, pp);
dictionary webster = new dictionary();
webster.put("assistantPlayerName", getName(player));
messageTo(storytellerPlayer, "handleStorytellerAssistantHasBeenAdded", webster, 0, false);
utils.setScriptVar(player, "storytellerAssistant", storytellerPlayer);
utils.setScriptVar(player, "storytellerAssistantName", storytellerName);
return;
}
// Storyteller Assistant Removal
void storyPlayerRemoveAssistant(obj_id storytellerPlayer, string storytellerName, obj_id player)
{
string_id message = new string_id ("storyteller", "assistant_removed_player");
prose_package pp = prose.getPackage(message, player, player);
prose.setTO(pp, storytellerName);
sendSystemMessageProse(player, pp);
utils.removeScriptVar(player, "storytellerAssistant");
utils.removeScriptVar(player, "storytellerAssistant");
dictionary webster = new dictionary();
webster.put("removedPlayerName", getName(player));
messageTo(storytellerPlayer, "handleStorytellerAssistantHasBeenRemoved", webster, 0, false);
return;
}
// Storyteller Invite to Story
int storyInviteSui(obj_id storytellerPlayer, string storytellerName, obj_id player)
{
string title = utils.packStringId(new string_id("storyteller", "sui_invite_title"));
prose_package pp = prose.getPackage(new string_id("storyteller", "sui_invite_body"));
prose.setTO(pp, storytellerName);
string msg = "\0" + packOutOfBandProsePackage(null, pp);
int pid = sui.msgbox(storytellerPlayer, player, msg, 2, title, sui.YES_NO, "storyInviteHandler");
return pid;
}
void storyInviteAcepted(obj_id storytellerPlayer, string storytellerName, obj_id player, obj_id storytellerAssistant)
{
string_id message = new string_id ("storyteller", "player_invited_name");
prose_package pp = prose.getPackage(message, player, player);
prose.setTO(pp, storytellerName);
sendSystemMessageProse(player, pp);
dictionary webster = new dictionary();
webster.put("addedPlayerName", getName(player));
webster.put("storytellerName", storytellerName);
if ( isIdValid(storytellerAssistant) )
{
messageTo(storytellerAssistant, "handleStorytellerPlayerHasBeenAdded", webster, 0, false);
}
else
{
messageTo(storytellerPlayer, "handleStorytellerPlayerHasBeenAdded", webster, 0, false);
}
utils.setScriptVar(player, "storytellerid", storytellerPlayer);
utils.setScriptVar(player, "storytellerName", storytellerName);
showStorytellerEffectsInAreaToPlayer(player, storytellerPlayer);
return;
}
// Storyteller Removal from Story
void storyPlayerRemovedFromStory(obj_id storytellerPlayer, string storytellerName, obj_id player)
{
string_id message = new string_id ("storyteller", "removed_from_story");
prose_package pp = prose.getPackage(message, player, player);
prose.setTO(pp, storytellerName);
sendSystemMessageProse(player, pp);
utils.removeScriptVar(player, "storytellerid");
utils.removeScriptVar(player, "storytellerName");
dictionary webster = new dictionary();
webster.put("removedPlayerName", getName(player));
messageTo(storytellerPlayer, "handleStorytellerPlayerHasBeenRemoved", webster, 0, false);
return;
}
/***************************************************************************/
boolean storytellerCombatCheck(obj_id attacker, obj_id target)
{
// storyteller combat is a player or his pet/beast fighting an npc.
// Completely pve, so find out which is the player and which is the npc.
if (!isIdValid(attacker) || !exists(attacker) || !isIdValid(target) || !exists(target))
return false;
obj_id storyPlayer = null;
obj_id storyNpc = null;
if ( isPlayer(attacker) )
{
// pvp is not effected by storytelling
if ( isPlayer(target) )
{
return true;
}
else
{
storyPlayer = attacker;
storyNpc = target;
}
}
else if ( isPlayer(target) )
{
storyPlayer = target;
storyNpc = attacker;
}
// neither attacker or target are players at this point, but is either a player controlled pet or beast?
else if ( pet_lib.isPet(attacker) || beast_lib.isBeast(attacker) )
{
// pets fighting pets is pvp and not effected by storytelling
if ( pet_lib.isPet(target) || beast_lib.isBeast(target) )
{
return true;
}
else
{
storyPlayer = getMaster(attacker);
storyNpc = target;
}
}
else if ( pet_lib.isPet(target) || beast_lib.isBeast(target) )
{
storyPlayer = getMaster(target);
storyNpc = attacker;
}
// check for remote egg used for area of effect and delayed attacks
// or destructible objects
else if ( !isMob(attacker) )
{
if ( hasScript(attacker, "systems.combat.combat_delayed_tracker") )
{
storyPlayer = utils.getObjIdScriptVar(attacker, "objOwner");
storyNpc = target;
}
else
{
storyNpc = attacker;
storyPlayer = target;
}
}
else if ( !isMob(target) )
{
if ( hasScript(target, "systems.combat.combat_delayed_tracker") )
{
storyPlayer = utils.getObjIdScriptVar(target, "objOwner");
storyNpc = attacker;
}
else
{
storyNpc = target;
storyPlayer = attacker;
}
}
// if both attacker and target are mobs, but neither are pets, beasts or players,
// then check to see if they can assist.
// Storyteller mobs can only assist against other storyteller mobs
else if ( hasObjVar(attacker, "storytellerid") || hasObjVar(target, "storytellerid") )
{
if ( hasObjVar(attacker, "storytellerid") && hasObjVar(target, "storytellerid") )
{
obj_id attackerNpcStoryteller = getObjIdObjVar(attacker, "storytellerid");
obj_id targetNpcStoryteller = getObjIdObjVar(target, "storytellerid");
if ( attackerNpcStoryteller == targetNpcStoryteller )
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
// check to see
if ( isIdValid(storyPlayer) && isIdValid(storyNpc) )
{
if ( hasObjVar(storyNpc, "storytellerid") )
{
if ( utils.hasScriptVar(storyPlayer, "storytellerid") )
{
obj_id playerStorytellerId = utils.getObjIdScriptVar(storyPlayer, "storytellerid");
obj_id npcStorytellerId = getObjIdObjVar(storyNpc, "storytellerid");
if ( isIdValid(playerStorytellerId) && isIdValid(npcStorytellerId) && playerStorytellerId == npcStorytellerId )
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
}
return true;
}
/***** Storyteller Vendor functions *************************************************/
boolean displayAvailableStorytellerTokenTypes(obj_id player, obj_id storytellerVendor)
{
if ( getDistance(storytellerVendor, player) > 10.0f )
{
return false;
}
string title = utils.packStringId(new string_id("storyteller", "token_purchase_type_title"));
string prompt = utils.packStringId(new string_id("storyteller","token_purchase_type_prompt"));
int pid = sui.listbox(storytellerVendor, player, prompt, sui.OK_CANCEL, title, getTokenTypeNamesArray(), "msgStorytellerTokenTypeSelected");
if ( pid > -1 )
{
string scriptvar_path = "storytellerVendor." + player;
utils.setScriptVar(storytellerVendor, scriptvar_path + ".pid", pid);
return true;
}
return false;
}
string[] getTokenTypeNamesArray()
{
const string[] sid_storytellerTokenTypes = {"token_type_prop",
"token_type_persisted_effect",
"token_type_immediate_effect",
"token_type_combat_npc",
"token_type_flavor_npc",
"token_type_other",
"token_type_costume"};
resizeable string[] storytellerTokenTypes = new string[0];
for ( int i=0; i < sid_storytellerTokenTypes.length; i++ )
{
string tokenType = utils.packStringId(new string_id("storyteller", sid_storytellerTokenTypes[i]));
storytellerTokenTypes = utils.addElement(storytellerTokenTypes, tokenType);
}
return storytellerTokenTypes;
}
boolean displayStorytellerTokenPurchaseSUI(obj_id player, int tokenType, obj_id storytellerVendor)
{
if ( !isIdValid(player) || !isIdValid(storytellerVendor) )
{
return false;
}
if ( getDistance(storytellerVendor, player) > 10.0f )
{
return false;
}
string scriptvar_path = "storytellerVendor." + player;
if ( utils.hasScriptVar(storytellerVendor, scriptvar_path + ".pid") )
{
int oldpid = utils.getIntScriptVar(storytellerVendor, scriptvar_path + ".pid");
sui.closeSUI(player, oldpid);
utils.removeScriptVar(storytellerVendor, scriptvar_path + ".pid");
utils.removeBatchScriptVar(storytellerVendor, scriptvar_path + ".tokenReferences");
utils.removeBatchScriptVar(storytellerVendor, scriptvar_path + ".tokens");
utils.removeScriptVar(storytellerVendor, scriptvar_path + ".tokenType");
}
resizeable string[] tokenReferences = new string[0];
int num_items = dataTableGetNumRows(STORYTELLER_DATATABLE);
for (int i = 0; i < num_items; i++)
{
dictionary row = dataTableGetRow(STORYTELLER_DATATABLE, i);
if ( row != null && !row.isEmpty() )
{
int row_tokenType = row.getInt("type");
if ( row_tokenType == tokenType )
{
string token_reference = row.getString("name");
int cost = row.getInt("cost");
if ( cost > 0 )
{
tokenReferences = utils.addElement(tokenReferences, token_reference);
}
}
}
}
string[] tokenTypeNames = getTokenTypeNamesArray();
if (tokenReferences == null || tokenReferences.length < 1)
{
// There are no items available for the selected token type, so show the type selection sui
storyteller.displayAvailableStorytellerTokenTypes(player, storytellerVendor);
prose_package pp = prose.getPackage(new string_id("storyteller", "token_purchase_none_of_type"), tokenTypeNames[tokenType]);
sendSystemMessageProse(player, pp);
return false;
}
string prompt = getString(new string_id("storyteller","token_purchase_select_token"));
string[] alphabetizedTokenReferences = getAlphabetizedTokenList(utils.toStaticStringArray(tokenReferences), tokenType);
string[] alphabetizedTokens = getTokenNamesList(alphabetizedTokenReferences, tokenType, player);
string myHandler = "msgStorytellerTokenPurchaseSelected";
int pid = sui.listbox(storytellerVendor, player, prompt, sui.OK_CANCEL_REFRESH, tokenTypeNames[tokenType], alphabetizedTokens, myHandler, false, false);
if ( pid > -1 )
{
sui.listboxUseOtherButton(pid, "Back");
sui.showSUIPage(pid);
utils.setScriptVar(storytellerVendor, scriptvar_path + ".pid", pid);
utils.setBatchScriptVar(storytellerVendor, scriptvar_path + ".tokenReferences", alphabetizedTokenReferences);
utils.setBatchScriptVar(storytellerVendor, scriptvar_path + ".tokens", alphabetizedTokens);
utils.setScriptVar(storytellerVendor, scriptvar_path + ".tokenType", tokenType);
return true;
}
return false;
}
string[] getAlphabetizedTokenList(string[] tokenReferences, int tokenType)
{
string[] namesColonTokens = new string[tokenReferences.length];
for ( int i = 0; i < tokenReferences.length; i++ )
{
string temp = getString(new string_id("static_item_n", tokenReferences[i]))+ "|" + tokenReferences[i];
namesColonTokens[i] = temp;
}
Arrays.sort(namesColonTokens);
string[] finalList = new string[namesColonTokens.length];
for ( int j = 0; j < namesColonTokens.length; j++ )
{
string[] splitText = split(namesColonTokens[j], '|');
finalList[j] = splitText[1];
}
if ( tokenType == COSTUME )
{
// Mad, insane hackery...please just look away
string[] tempList = new string[finalList.length];
utils.copyArray(finalList, tempList);
finalList[0] = "item_costume_kit";
int nextFinalListSlot = 1;
for ( int k = 0; k < tempList.length; k++ )
{
string ref = tempList[k];
if ( !ref.equals("item_costume_kit") )
{
finalList[nextFinalListSlot] = ref;
++nextFinalListSlot;
}
}
}
return finalList;
}
string[] getTokenNamesList(string[] tokenReferences, int tokenType, obj_id player)
{
string[] tokenNamesList = new string[tokenReferences.length];
for ( int i = 0; i < tokenReferences.length; i++ )
{
string token = tokenReferences[i];
dictionary row = dataTableGetRow(STORYTELLER_DATATABLE, token);
if ( row != null && !row.isEmpty() )
{
int cost = row.getInt("cost");
string tokenName = utils.packStringId(new string_id("static_item_n", token));
if ( tokenType == COMBAT_NPC || tokenType == FLAVOR_NPC )
{
tokenName = tokenName + " (Cost: " + cost + " per npc)";
}
else if ( tokenType == PROP )
{
tokenName = tokenName + " (Cost: " + cost + " per prop)";
}
else if ( tokenType == COSTUME )
{
if ( token.equals("item_costume_kit") )
{
tokenName = tokenName + " (Cost: " + cost + " per holoshroud)";
}
else
{
// if the item is a costume that you alreqady know, list it in red text
dictionary itemData = new dictionary();
itemData = dataTableGetRow(static_item.ITEM_STAT_BALANCE_TABLE, token);
if ( itemData != null && !itemData.isEmpty() )
{
string costumeName = itemData.getString("buff_name");
if ( hasSkill(player, costumeName) )
{
string tokenText = utils.packStringId(new string_id("static_item_n", token));
string_id contrastText_sid = new string_id("storyteller","costume_already_known");
prose_package pp = prose.getPackage(contrastText_sid);
prose.setTO(pp, tokenText);
prose.setDI(pp, cost);
tokenName = "\0" + packOutOfBandProsePackage(null, pp);
}
else
{
tokenName = tokenName + " (Cost: " + cost + ")";
}
}
}
}
else
{
tokenName = tokenName + " (Cost: " + cost + ")";
}
tokenNamesList[i] = tokenName;
}
else
{
// this should never happen, but just in case
tokenNamesList[i] = utils.packStringId(new string_id("storyteller", "unknown_token")) + " : " + token;
}
}
return tokenNamesList;
}
void storytellerTokenPurchased(dictionary params, obj_id storytellerVendor)
{
if ( params == null || params.isEmpty() )
{
return;
}
obj_id player = sui.getPlayerId(params);
if ( !isIdValid(player) )
{
return;
}
if ( getDistance(storytellerVendor, player) > 10.0f )
{
return;
}
string scriptvar_path = "storytellerVendor." + player;
if ( !utils.hasScriptVar(storytellerVendor, scriptvar_path + ".pid") )
{
return;
}
int oldPid = utils.getIntScriptVar(storytellerVendor, scriptvar_path + ".pid");
string[] tokenReferences = utils.getStringBatchScriptVar(storytellerVendor, scriptvar_path + ".tokenReferences");
string[] tokens = utils.getStringBatchScriptVar(storytellerVendor, scriptvar_path + ".tokens");
int tokenType = utils.getIntScriptVar(storytellerVendor, scriptvar_path + ".tokenType");
utils.removeScriptVar(storytellerVendor, scriptvar_path + ".pid");
utils.removeBatchScriptVar(storytellerVendor, scriptvar_path + ".tokenReferences");
utils.removeBatchScriptVar(storytellerVendor, scriptvar_path + ".tokens");
utils.removeScriptVar(storytellerVendor, scriptvar_path + ".tokenType");
if ( tokenReferences == null || tokenReferences.length == 0 )
{
LOG("LOG_CHANNEL", "storyteller::storytellerTokenPurchased -- the token reference list is null.");
return;
}
int button = sui.getIntButtonPressed(params);
if ( button == sui.BP_CANCEL )
{
return;
}
if ( button == sui.BP_REVERT )
{
// Go back the Token Type Selection list
storyteller.displayAvailableStorytellerTokenTypes(player, storytellerVendor);
return;
}
int token_selected = sui.getListboxSelectedRow(params);
if (token_selected < 0)
return;
if (token_selected >= tokenReferences.length)
return;
// Get the selected item.
string token_reference = tokenReferences[token_selected];
if (token_reference == null)
{
LOG("LOG_CHANNEL", "storyteller::storytellerTokenPurchased -- the item template selected by " + storytellerVendor + " is null.");
return;
}
// Get token data for the selected item.
int tokenIdx = dataTableSearchColumnForString(token_reference, "name", STORYTELLER_DATATABLE);
if (tokenIdx == -1)
{
LOG("LOG_CHANNEL", "storyteller::storytellerTokenPurchased -- cannot find " + token_reference + " in the storyteller token datatable.");
return;
}
// Get static item data for the selected item.
int staticIdx = dataTableSearchColumnForString(token_reference, "name", STORYTELLER_DATATABLE);
if (staticIdx == -1)
{
LOG("LOG_CHANNEL", "storyteller::storytellerTokenPurchased -- cannot find " + token_reference + " in the static item datatable.");
return;
}
dictionary tokenData = dataTableGetRow(STORYTELLER_DATATABLE, tokenIdx);
int cost = tokenData.getInt("cost");
string tokenName = utils.packStringId(new string_id("static_item_n", token_reference));
int maxCharges = tokenData.getInt("max_charges");
if ( requestNumCharges(tokenType, token_reference) && maxCharges > 1 )
{
string prompt = getString(new string_id("storyteller","token_how_many_charges")) + maxCharges;
int pid = sui.inputbox(storytellerVendor, player, prompt, sui.OK_CANCEL, tokenName, sui.INPUT_NORMAL, null, "msgStorytellerChargesSelected");
if ( pid > -1 )
{
sui.showSUIPage(pid);
utils.setScriptVar(storytellerVendor, scriptvar_path + ".pid", pid);
utils.setScriptVar(storytellerVendor, scriptvar_path + ".tokenChosen", token_reference);
utils.setScriptVar(storytellerVendor, scriptvar_path + ".tokenType", tokenType);
return;
}
}
givePurchasedToken(storytellerVendor, player, token_reference, tokenName, cost, 0);
storyteller.displayStorytellerTokenPurchaseSUI(player, tokenType, storytellerVendor);
return;
}
boolean requestNumCharges(int tokenType, string token_reference)
{
if ( tokenType == COMBAT_NPC )
return true;
if ( tokenType == FLAVOR_NPC )
return true;
if ( tokenType == PROP )
return true;
// standard holoshroud
// if more special case tokens needs to be added, change this to an array to be checked against
if ( token_reference.equals("item_costume_kit") )
return true;
return false;
}
void storytellerSellTokenWithCharges(dictionary params, obj_id storytellerVendor)
{
obj_id player = sui.getPlayerId(params);
int btn = sui.getIntButtonPressed(params);
string text = sui.getInputBoxText(params);
int numCharges = utils.stringToInt(text);
string scriptvar_path = "storytellerVendor." + player;
string token_reference = utils.getStringScriptVar(storytellerVendor, scriptvar_path + ".tokenChosen");
int tokenType = utils.getIntScriptVar(storytellerVendor, scriptvar_path + ".tokenType");
string tokenName = utils.packStringId(new string_id("static_item_n", token_reference));
dictionary tokenData = dataTableGetRow(STORYTELLER_DATATABLE, token_reference);
int cost = tokenData.getInt("cost");
int maxCharges = tokenData.getInt("max_charges");
if ( btn == sui.BP_CANCEL )
{
storyteller.displayStorytellerTokenPurchaseSUI(player, tokenType, storytellerVendor);
return;
}
if (numCharges < 1 || numCharges > maxCharges)
{
string_id message = new string_id ("storyteller", "token_num_charges_invalid");
prose_package pp = prose.getPackage(message, player, player);
prose.setDI(pp, maxCharges);
sendSystemMessageProse(player, pp);
string prompt = getString(new string_id("storyteller","token_how_many_charges")) + maxCharges;
int pid = sui.inputbox(storytellerVendor, player, prompt, sui.OK_CANCEL, tokenName, sui.INPUT_NORMAL, null, "msgStorytellerChargesSelected");
if ( pid > -1 )
{
sui.showSUIPage(pid);
utils.setScriptVar(storytellerVendor, scriptvar_path + ".pid", pid);
utils.setScriptVar(storytellerVendor, scriptvar_path + ".tokenChosen", token_reference);
utils.setScriptVar(storytellerVendor, scriptvar_path + ".tokenType", tokenType);
}
}
else
{
givePurchasedToken(storytellerVendor, player, token_reference, tokenName, cost*numCharges, numCharges);
storyteller.displayStorytellerTokenPurchaseSUI(player, tokenType, storytellerVendor);
}
return;
}
void givePurchasedToken(obj_id storytellerVendor, obj_id player, string tokenReference, string tokenName, int cost, int numCharges)
{
obj_id inv = getObjectInSlot(player, "inventory");
if ( !isIdValid(inv) )
{
LOG("LOG_CHANNEL", "storyteller::storytellerTokenPurchased -- " + player + "'s inventory object is null.");
return;
}
// Check player for required credits
if ( !money.hasFunds(player, money.MT_TOTAL, cost) )
{
prose_package pp = prose.getPackage(new string_id("storyteller", "token_purchase_not_enough_credits"), tokenName);
sendSystemMessageProse(player, pp);
}
else
{
// Check for inventory space.
int free_space = getVolumeFree(inv);
if (free_space < 1)
{
sendSystemMessage(player, faction_perk.SID_INVENTORY_FULL);
//factions.addFactionStanding(player, faction, cost);
return;
}
// Pay the costs
utils.moneyOutMetric(player, "STORYTELLER_TOKENS", cost);
money.requestPayment(player, storytellerVendor, cost, "pass_fail", null, true);
CustomerServiceLog("storyteller", "(" + player + ")" + getName(player) + " is attempting to purchase item: " + tokenReference);
CustomerServiceLog("storyteller", "(" + player + ")" + getName(player) + "'s purchase cost: " + cost);
// Create the item.
// Check if it's a static item, if so create with that function instead.
obj_id item = static_item.createNewItemFunction(tokenReference, inv);
if ( !isIdValid(item) )
{
LOG("LOG_CHANNEL", "storyteller::storytellerTokenPurchased -- unable to create " + tokenReference + " for " + storytellerVendor);
//factions.addFactionStanding(player, faction, cost);
CustomerServiceLog("storyteller", "(" + player + ")" + getName(player) + "'s purchase of " + tokenReference + " has failed!");
return;
}
if ( numCharges > 0 )
{
setCount(item, numCharges);
}
CustomerServiceLog("storyteller", "(" + player + ")" + getName(player) + " has purchased (" + item + ")" + getName(item));
logBalance("storyteller;" + getGameTime() + ";item;" + tokenReference + ";" + cost);
// Send the completion message.
prose_package pp = prose.getPackage(new string_id("storyteller", "token_purchase_complete"), player, item);
sendSystemMessageProse(player, pp);
}
return;
}
/***** END Storyteller Vendor functions *************************************************/
/***************************************************************************/
//Confirms the proper amount of time has passed before destroying a storyteller object.
//this is used in case there is a delayed response from a City when checking for a
//city specialization (which increases exist time by 12 hours)
void confirmCleanuptime(obj_id object)
{
//initialize variables
int storytellerCreationTime = 0;
int existTime = 0;
//creation time.
if(hasObjVar(object, "storytellerCreationTime"))
storytellerCreationTime = getIntObjVar(object, "storytellerCreationTime");
//length of time it should exist in the world(in seconds)
if(hasObjVar(object, "storytellerCleanUpTime"))
existTime = getIntObjVar(object, "storytellerCleanUpTime");
if(storytellerCreationTime + existTime > getGameTime())
{
int timeRemaining = storytellerCreationTime + existTime - getGameTime();
//we are not ready to clean up yet - send a new MessageTo with the actual cleanup Time.
messageTo(object, "prepCleanupProp", null, timeRemaining, false);
return;
}
trial.cleanupObject(object);
}
//City Specialization increases exist time by 12 hours.
void setBonusExistTime(obj_id self)
{
if(hasObjVar(self, "storytellerCleanUpTime"))
{
//add bonus time (12 hours) for the specialization
int cleanUpTime = getIntObjVar(self, "storytellerCleanUpTime");
cleanUpTime += 43200;
setObjVar(self, "storytellerCleanUpTime", cleanUpTime);
}
}
//determines if a ST Prop is in a city and messages city to check specialization status
void calculatePropBonusExistTime(obj_id object)
{
//if we are in a city, we get bonus time
int cleanUpTime = DEFAULT_PROP_CLEANUP_TIME;
int city_id = getCityAtLocation(getLocation(object), 0);
if(city_id > 0)
{
//we are in a city
cleanUpTime += 28800; //give them an extra 8 hours.
//message the City Hall to see if a Specialization increases time.
obj_id cityHall = cityGetCityHall(city_id);
dictionary outparams = new dictionary();
outparams.put("queryObject", object);
messageTo(cityHall, "st_citySpecBonusCheck", outparams, 0.0f, false);
}
setObjVar(object, "storytellerCleanUpTime", cleanUpTime);
}
//determines if a ST NPC is in a city and messages city to check specialization status
void calculateNpcBonusExistTime(obj_id object)
{
//if we are in a city, we get bonus time
int cleanUpTime = DEFAULT_NPC_CLEANUP_TIME;
int city_id = getCityAtLocation(getLocation(object), 0);
if(city_id > 0)
{
//we are in a city
cleanUpTime += 28800; //give them an extra 8 hours.
//message the City Hall to see if a Specialization increases time.
obj_id cityHall = cityGetCityHall(city_id);
dictionary outparams = new dictionary();
outparams.put("queryObject", object);
messageTo(cityHall, "st_citySpecBonusCheck", outparams, 0.0f, false);
}
setObjVar(object, "storytellerCleanUpTime", cleanUpTime);
}
/***************************************************************************/