uox3/data/js/server/global.js
Dragon Slayer 5a81d7b704 cleanup
2026-04-25 09:39:39 -05:00

301 lines
No EOL
8.9 KiB
JavaScript

/// <reference path="../definitions.d.ts" />
// @ts-check
// Global Script
// Supported Events trigger for every character/item, use with care
const questSystemEnabled = GetServerSetting( "QuestSystemEnabled" );
const loginQuestEnabled = GetServerSetting( "LoginQuestEnabled" );
/** @type { ( sockPlayer: Socket, pPlayer: Character ) => boolean } */
function onLogin( socket, pChar )
{
const coreShardEra = EraStringToNum( GetServerSetting( "CoreShardEra" ));
const youngPlayerSystem = GetServerSetting( "YoungPlayerSystem" );
// Display Admin Welcome Gump for characters on admin account, until a choice has been made
if( pChar.accountNum == 0 )
{
// Check if startupChoice has been saved in shared folder
var seenWelcome = CheckCustomGlobalData( "welcomeGumpChoiceMade.jsdata", "seenWelcome" );
if( !seenWelcome )
{
// Admin has either not seen or reacted to welcome gump yet
TriggerEvent( 1, "DisplayAdminWelcomeGump", socket, pChar );
}
}
// If it's first time player logs in with this character since server startup,
// or in at least 6 hours, give them a small boost to hunger level to avoid
// instant starving/hunger on login
let currentClock = GetCurrentClock();
if( pChar.hunger == 0 )
{
let oldLoginTime = pChar.GetTempTag( "loginTime" );
if( oldLoginTime == 0 || ( currentClock / 1000 / 60 ) - oldLoginTime > 360 )
{
pChar.hunger = 1;
}
}
// Store login timestamp (in minutes) in temp tag
var loginTime = Math.round( currentClock / 1000 / 60 );
pChar.SetTempTag( "loginTime", loginTime );
// Attach OnFacetChange to characters logging into the shard
if( !pChar.HasScriptTrigger( 2508 ))
{
pChar.AddScriptTrigger( 2508 );
}
if( youngPlayerSystem && pChar.account.isYoung )
{
// Attach "Young" player script, if the account is young and does not have script
if( !pChar.HasScriptTrigger( 8001 ))
{
pChar.AddScriptTrigger( 8001 );
}
// Check if "Young" player still meets requirement for being considered young
TriggerEvent( 8001, "CheckYoungStatus", socket, pChar, true );
}
else if( !youngPlayerSystem )
{
// Remove young player script if system is inactive
pChar.RemoveScriptTrigger( 8001 );
}
if( coreShardEra >= EraStringToNum( "aos" ) && ( !pChar.npc && !pChar.HasScriptTrigger( 7001 )))// Attach the special moves Book
{
pChar.AddScriptTrigger( 7001 );
}
// Re-adds Buff for disguise kit if player still has time left.
var disguiseKitTime = pChar.GetJSTimer( 1, 5023 );
if( disguiseKitTime > 0 )
{
var currentTime = GetCurrentClock();
var timeLeft = Math.round(( disguiseKitTime - currentTime ) / 1000 );
TriggerEvent( 2204, "RemoveBuff", pChar, 1033 );
TriggerEvent( 2204, "AddBuff", pChar, 1033, 1075821, 1075820, timeLeft, "" );
}
// Attach OnQuest Toggle
if( questSystemEnabled && !pChar.HasScriptTrigger( 5805 ) )
{
pChar.AddScriptTrigger( 5805 );
}
// Repair and validate active quests on login
if( questSystemEnabled )
{
TriggerEvent( 5800, "ValidateTimedQuestsOnLogin", pChar );
TriggerEvent( 5800, "RestoreQuestPlayerTriggersOnLogin", pChar );
TriggerEvent( 5800, "ValidateEscortQuestsOnLogin", pChar );
TriggerEvent( 5800, "ValidateGuidedWalkQuestsOnLogin", pChar );
TriggerEvent( 5800, "ValidateRaceQuestsOnLogin", pChar );
}
if( questSystemEnabled && loginQuestEnabled )
{
// Show the login quest gump
TriggerEvent( 5813, "LoginQuest", pChar );
}
}
/** @type { ( sockPlayer: Socket, pPlayer: Character ) => boolean } */
function onLogout( pSock, pChar )
{
var minSinceLogin = Math.round( GetCurrentClock() / 1000 / 60 ) - parseInt( pChar.GetTempTag( "loginTime" ));
pChar.playTime += minSinceLogin;
pChar.account.totalPlayTime += minSinceLogin;
//Used to remove the candy timer in items/candy.js
pChar.KillJSTimer( 0, 5601 );
pChar.SetTempTag( "toothach", null );
pChar.SetTempTag( "Acidity", null );
//Treasure Hunting Kill Event.
var dirtItem = CalcItemFromSer( parseInt( pChar.GetTempTag( "dirtMadeSer" )));
if( ValidateObject( dirtItem ))
{
TriggerEvent( 5405, "KillTreasureEvent", dirtItem, pChar );
return;
}
}
/** @type { ( thingCreated: BaseObject, thingType: 0 | 1 ) => void } */
function onCreatePlayer( pChar )
{
const coreShardEra = EraStringToNum( GetServerSetting( "CoreShardEra" ));
const youngPlayerSystem = GetServerSetting( "YoungPlayerSystem" );
// If player character is created on a Young account, give them Young-specific items
if( youngPlayerSystem && pChar.account.isYoung )
{
// Attach "Young" player script, if the account is young and does not have script
if( !pChar.HasScriptTrigger( 8001 ))
{
pChar.AddScriptTrigger( 8001 );
}
TriggerEvent( 8001, "GiveYoungPlayerItems", pChar.socket, pChar );
}
//Attach the special moves Book
if( coreShardEra >= EraStringToNum( "aos" ) && ( !pChar.npc && !pChar.HasScriptTrigger( 7001 )))
{
pChar.AddScriptTrigger( 7001 );
}
}
// Generic global-script function to look up data in /shared/jsWorldData/ folder
function CheckCustomGlobalData( fileName, dataToCheck )
{
var rValue = false;
var mFile = new UOXCFile();
mFile.Open( fileName, "r", "jsWorldData" );
if( mFile && mFile.Length() >= 0 )
{
// Read until we reach end of the file
while( !mFile.EOF() )
{
// Read a line of text from the file
var line = mFile.ReadUntil( "\n" );
if( line.length <= 1 || line == "" )
continue;
var splitString = line.split( "=" );
if( splitString[0] && splitString[0].toLowerCase() == dataToCheck.toLowerCase() )
{
if( splitString[1] )
{
// Return value
rValue = splitString[1];
}
}
}
// Close file and free up memory allocated by file object
mFile.Close();
// Free memory allocated by file object
mFile.Free();
}
return rValue;
}
// Fetch corpsedecaytimer from uox.ini
const corpseDecayTimer = GetServerSetting( "CORPSEDECAYTIMER" );
const playerCorpseIDs = [ 0x0190, 0x0191, 0x025D, 0x025E, 0x029A, 0x029B ];
// Handle turning player corpses into bones
/** @type { ( decaying: Item ) => boolean } */
function onDecay( iDecaying )
{
// If not a corpse, or if corpse has no owner (i.e. NPC corpse), allow code to decay item like normal
if( !iDecaying.corpse || !ValidateObject( iDecaying.owner ))
return true;
if( iDecaying.id == 0x2006 && playerCorpseIDs.indexOf( iDecaying.amount ) > -1 ) // character IDs are stored on corpses in amount property!
{
// We have a player corpse on our hands! Turn it into bones, and reset decay timer
iDecaying.decaytime = corpseDecayTimer;
// Add appropriate bones based on the direction the corpse lies in
switch( iDecaying.dir )
{
case 4: // North, on back
case 128: // North, on belly
iDecaying.id = 0x0ecd;
break;
case 5: // North-East, on back
case 129: // North-East, on belly
iDecaying.id = 0x0ecf;
break;
case 6: // East, on back
case 130: // East, on belly
iDecaying.id = 0x0ecb;
break;
case 7: // South-East, on back
case 131: // South-East, on belly
iDecaying.id = 0x0ece;
break;
case 8: // South, on back
case 132: // South, on belly
iDecaying.id = 0x0eca;
break;
case 1: // South-West, on back
case 133: // South-West, on belly
iDecaying.id = 0x0ed0;
break;
case 2: // West, on back
case 134: // West, on belly
iDecaying.id = 0x0ecc;
break;
case 3: // North-West, on back
case 135: // North-west on belly
iDecaying.id = 0x0ece;
break;
default:
break;
}
return false;
}
return true;
}
// Override the hard-coded help menu and display a JS based one
/** @type { ( mChar: Character ) => boolean } */
function onHelpButton( pChar )
{
TriggerEvent( 2, "DisplayHelpMenu", pChar );
return false;
}
// Override hard-coded snooping request and go with scripted one
/** @type { ( snooped: Character, pack: Item, snooper: Character ) => boolean } */
function onSnoopAttempt( snoopTarget, targCont, pUser )
{
return TriggerEvent( 4055, "SnoopAttempt", snoopTarget, targCont, pUser );
}
// Look for Gem of Salvation in player's backpack to give them chance to resurrect
/** @type { ( pDead: Character, iCorpse: Item ) => boolean } */
function onDeath( pDead, iCorpse )
{
if( !ValidateObject( pDead ) || pDead.npc || !pDead.online )
return false;
return TriggerEvent( 5045, "onDeath", pDead, iCorpse );
}
// Triggers based on bandage macro in client
/** @type { ( mSock: Socket, targChar: Character, bandageItem: Item ) => boolean } */
function onUseBandageMacro( pSock, targChar, bandageItem )
{
if( pSock != null && ValidateObject( targChar ) && ValidateObject( bandageItem ) && bandageItem.amount >= 1 )
{
var pUser = pSock.currentChar;
if( ValidateObject( pUser ))
{
TriggerEvent( 4000, "onUseCheckedTriggered", pUser, targChar, bandageItem );
}
}
return true;
}
/** @type { ( mChar: Character ) => boolean } */
function onQuestGump( pUser )
{
if( questSystemEnabled )
{
if( ValidateObject( pUser ) && !pUser.dead )
{
TriggerEvent( 5803, "QuestMenu", pUser );
}
else
{
pUser.SysMessage( "Something is wrong, pUser is not valid or is dead." );
}
}
}