From 9c87ff950c35baa5196286167ccf40a5150871da Mon Sep 17 00:00:00 2001 From: Vortrex <3858226+VortrexFTW@users.noreply.github.com> Date: Thu, 9 Sep 2021 01:37:04 -0500 Subject: [PATCH] Lots of fixes + clans * Added clans * Fixed interior exit labels * Disabled nametags on games without 3D label support * Fixed mouse cursor toggle command * Fixed SA fight-style not being applied * Added manageRanks clan permission bitflag * Added interior lights toggle * Fixed clan chat * Added real-time support with optional timezone offset * Added lots of JSDoc stuff * Added command for managers to set server GUI colour * Added GeoIP command for admins * Added command for admins to force an immediate payday * Added admins gotospawn command * Added return player command for teleported players * Added pizza delivery job const * Fixed biz/house set pickup & interior type * Fixed inventory showing ammo count for melee weapons * Fixed SA using wrong pickup types * Fixed char select screen breaking when in a clan * Added +/- symbol util for number display * Added get current timestamp for timezone offset util * Fixed vehicle owner ID being set wrong for job veh --- scripts/client/label.js | 4 +- scripts/client/nametag.js | 4 + scripts/client/server.js | 2 +- scripts/client/sync.js | 2 +- scripts/client/utilities.js | 6 +- scripts/server/bitflag.js | 1 + scripts/server/business.js | 20 +- scripts/server/chat.js | 4 +- scripts/server/clan.js | 390 +++++++++++++++++++++++++++++----- scripts/server/class.js | 11 +- scripts/server/colour.js | 61 +++++- scripts/server/command.js | 20 +- scripts/server/config.js | 190 ++++++++++++++++- scripts/server/const.js | 1 + scripts/server/economy.js | 20 +- scripts/server/event.js | 4 +- scripts/server/help.js | 1 + scripts/server/house.js | 86 ++++---- scripts/server/item.js | 16 +- scripts/server/messaging.js | 2 +- scripts/server/misc.js | 8 +- scripts/server/moderation.js | 46 +++- scripts/server/native/gtac.js | 15 +- scripts/server/subaccount.js | 30 ++- scripts/server/timers.js | 18 +- scripts/server/utilities.js | 27 ++- scripts/server/vehicle.js | 9 +- scripts/shared/const.js | 2 +- 28 files changed, 835 insertions(+), 165 deletions(-) diff --git a/scripts/client/label.js b/scripts/client/label.js index bfcc9d3a..d2d1be1e 100644 --- a/scripts/client/label.js +++ b/scripts/client/label.js @@ -7,8 +7,6 @@ // TYPE: Client (JavaScript) // =========================================================================== -"use strict"; - let businessLabels = []; let houseLabels = []; let jobLabels = []; @@ -165,7 +163,7 @@ function renderPropertyExitLabel(position) { } let text = "EXIT"; - size = propertyLabelNameFont.measure(text, game.width, 0.0, 0.0, propertyLabelNameFont.size, true, true); + let size = propertyLabelNameFont.measure(text, game.width, 0.0, 0.0, propertyLabelNameFont.size, true, true); propertyLabelNameFont.render(text, [screenPosition.x-size[0]/2, screenPosition.y-size[1]/2], game.width, 0.0, 0.0, propertyLabelNameFont.size, COLOUR_WHITE, false, true, false, true); } diff --git a/scripts/client/nametag.js b/scripts/client/nametag.js index 6412eea7..f37e0f49 100644 --- a/scripts/client/nametag.js +++ b/scripts/client/nametag.js @@ -140,6 +140,10 @@ function drawNametag(x, y, health, armour, text, ping, alpha, distance, colour, // =========================================================================== function updateNametags(element) { + if(!areWorldLabelsSupported()) { + return false; + } + if(localPlayer != null) { let playerPos = localPlayer.position; let elementPos = element.position; diff --git a/scripts/client/server.js b/scripts/client/server.js index 41e183ee..2fa152a8 100644 --- a/scripts/client/server.js +++ b/scripts/client/server.js @@ -50,7 +50,7 @@ function addAllNetworkHandlers() { addNetworkHandler("vrr.drunkEffect", setLocalPlayerDrunkEffect); addNetworkHandler("vrr.showItemActionDelay", showItemActionDelay); addNetworkHandler("vrr.set2DRendering", setPlayer2DRendering); - addNetworkHandler("vrr.mouseCursor", setMouseCursorState); + addNetworkHandler("vrr.mouseCursor", toggleMouseCursor); addNetworkHandler("vrr.mouseCamera", setMouseCameraState); addNetworkHandler("vrr.weaponDamageEnabled", setPlayerWeaponDamageEnabled); addNetworkHandler("vrr.weaponDamageEvent", setPlayerWeaponDamageEvent); diff --git a/scripts/client/sync.js b/scripts/client/sync.js index 2abb343b..5244432c 100644 --- a/scripts/client/sync.js +++ b/scripts/client/sync.js @@ -227,7 +227,7 @@ function syncPlayerProperties(player) { if(getGame() == GAME_GTA_SA) { if(doesEntityDataExist(player, "vrr.fightStyle")) { let fightStyle = getEntityData(player, "vrr.fightStyle"); - player.fightStyle = fightStyle; + player.setFightStyle(fightStyle[0], fightStyle[1]); } } diff --git a/scripts/client/utilities.js b/scripts/client/utilities.js index 83c6f7d6..70cb2a18 100644 --- a/scripts/client/utilities.js +++ b/scripts/client/utilities.js @@ -443,9 +443,9 @@ function setMouseCameraState(state) { // =========================================================================== -function setMouseCursorState(state) { - logToConsole(LOG_DEBUG, `[VRR.Utilities] ${(state)?"Enabled":"Disabled"} mouse cursor`); - gui.showCursor(state, !state); +function toggleMouseCursor() { + logToConsole(LOG_DEBUG, `[VRR.Utilities] ${(!gui.cursorEnabled)?"Enabled":"Disabled"} mouse cursor`); + gui.showCursor(!gui.cursorEnabled, gui.cursorEnabled); } // =========================================================================== diff --git a/scripts/server/bitflag.js b/scripts/server/bitflag.js index 1e4b7793..a8b48329 100644 --- a/scripts/server/bitflag.js +++ b/scripts/server/bitflag.js @@ -100,6 +100,7 @@ let serverBitFlagKeys = { "manageHouses", "manageBusinesses", "manageNPCs", + "manageRanks", "owner", ], accountSettingsFlagKeys: [ diff --git a/scripts/server/business.js b/scripts/server/business.js index 5845e8b4..f55d6e46 100644 --- a/scripts/server/business.js +++ b/scripts/server/business.js @@ -379,12 +379,12 @@ function lockUnlockBusinessCommand(command, params, client) { return false; } - getBusinessData(businessId).interiorLights = !getBusinessData(houseId).interiorLights; + getBusinessData(businessId).interiorLights = !getBusinessData(businessId).interiorLights; getBusinessData(businessId).needsSaved = true; updateBusinessInteriorLightsForOccupants(businessId); - messagePlayerMeAction(client, `turns ${getOnOffFromBool(getBusinessData(businessId).interiorLights)} the business lights`); + meActionToNearbyPlayers(client, `turns ${toLowerCase(getOnOffFromBool(getBusinessData(businessId).interiorLights))} the business lights`); } // =========================================================================== @@ -490,6 +490,8 @@ function setBusinessInteriorTypeCommand(command, params, client) { if(isNaN(typeParam)) { if(toLowerCase(typeParam) == "none") { + removePlayersFromBusiness(businessId); + getBusinessData(businessId).exitPosition = toVector3(0.0, 0.0, 0.0); getBusinessData(businessId).exitInterior = 0; getBusinessData(businessId).hasInterior = false; @@ -497,17 +499,8 @@ function setBusinessInteriorTypeCommand(command, params, client) { resetBusinessPickups(); resetBusinessBlips(); - return false; - } else if(toLowerCase(typeParam) == "teleport") { - getBusinessData(businessId).exitPosition = getPlayerPosition(client); - getBusinessData(businessId).exitInterior = getPlayerInterior(client); - getBusinessData(businessId).exitDimension = getBusinessData(businessId).databaseId+getGlobalConfig().businessDimensionStart; - getBusinessData(businessId).hasInterior = true; - messageAdmins(`${getInlineChatColourByName("lightGrey")}${getPlayerName(client)} ${getInlineChatColourByName("white")}removed business ${getInlineChatColourByType("businessBlue")}${getBusinessData(businessId).name} ${getInlineChatColourByName("white")}interior`); - resetBusinessPickups(); - resetBusinessBlips(); - return true; + return false; } if(isNull(getGameConfig().interiorTemplates[getServerGame()][typeParam])) { @@ -516,6 +509,7 @@ function setBusinessInteriorTypeCommand(command, params, client) { return false; } + removePlayersFromBusiness(businessId); messageAdmins(`${getInlineChatColourByName("lightGrey")}${getPlayerName(client)} ${getInlineChatColourByName("white")}set business ${getInlineChatColourByType("businessBlue")}${getBusinessData(businessId).name} ${getInlineChatColourByName("white")}interior type to ${getInlineChatColourByName("lightGrey")}${toLowerCase(typeParam)}`); getBusinessData(businessId).exitPosition = getGameConfig().interiorTemplates[getServerGame()][typeParam].exitPosition; getBusinessData(businessId).exitInterior = getGameConfig().interiorTemplates[getServerGame()][typeParam].exitInterior; @@ -529,6 +523,8 @@ function setBusinessInteriorTypeCommand(command, params, client) { messagePlayerError(client, "Business ID not found!"); return false; } + + removePlayersFromBusiness(businessId); getBusinessData(businessId).exitPosition = getBusinessData(businessId).exitPosition; getBusinessData(businessId).exitInterior = getBusinessData(businessId).exitInterior; getBusinessData(businessId).exitDimension = getBusinessData(businessId).databaseId+getGlobalConfig().businessDimensionStart; diff --git a/scripts/server/chat.js b/scripts/server/chat.js index 0dfbfbb9..9742042e 100644 --- a/scripts/server/chat.js +++ b/scripts/server/chat.js @@ -203,8 +203,8 @@ function meActionToNearbyPlayers(client, messageText) { function clanChat(client, messageText) { let clients = getClients(); for(let i in clients) { - if(getPlayerCurrentSubAccount(client).clan != getPlayerCurrentSubAccount(clients[i]).clan) { - messageClientClanChat(clients[i], client, messageText); + if(arePlayersInSameClan(client, clients[i])) { + messagePlayerClanChat(clients[i], client, messageText); } } } diff --git a/scripts/server/clan.js b/scripts/server/clan.js index 6cace7f1..23be34e9 100644 --- a/scripts/server/clan.js +++ b/scripts/server/clan.js @@ -30,7 +30,7 @@ function loadClansFromDatabase() { if(dbQuery.numRows > 0) { while(dbAssoc = fetchQueryAssoc(dbQuery)) { let tempClanData = new serverClasses.clanData(dbAssoc); - tempClanData.members = loadClanMembersFromDatabase(tempClanData.databaseId); + //tempClanData.members = loadClanMembersFromDatabase(tempClanData.databaseId); tempClanData.ranks = loadClanRanksFromDatabase(tempClanData.databaseId); tempClans.push(tempClanData); logToConsole(LOG_VERBOSE, `[VRR.Clan]: Clan '${tempClanData.name}' loaded from database successfully!`); @@ -60,8 +60,6 @@ function loadClanMembersFromDatabase() { if(dbQuery.numRows > 0) { while(dbAssoc = fetchQueryAssoc(dbQuery)) { let tempClanData = new serverClasses.clanData(dbAssoc); - tempClanData.members = loadClanMembersFromDatabase(tempClanData.databaseId); - tempClanData.ranks = loadClanRanksFromDatabase(tempClanData.databaseId); tempClans.push(tempClanData); logToConsole(LOG_VERBOSE, `[VRR.Clan]: Clan '${tempClanData.name}' loaded from database successfully!`); } @@ -88,10 +86,11 @@ function loadClanRanksFromDatabase(clanDatabaseId) { let dbQuery = queryDatabase(dbConnection, `SELECT * FROM clan_rank WHERE clan_rank_clan = ${clanDatabaseId}`); if(dbQuery) { if(dbQuery.numRows > 0) { - let dbAssoc = fetchQueryAssoc(dbQuery) - let tempClanRankData = new serverClasses.clanRankData(dbAssoc); - tempClanRanks.push(tempClanRankData); - logToConsole(LOG_VERBOSE, `[VRR.Clan]: Clan rank '${tempClanRankData.name}' loaded from database successfully!`); + while(dbAssoc = fetchQueryAssoc(dbQuery)) { + let tempClanRankData = new serverClasses.clanRankData(dbAssoc); + tempClanRanks.push(tempClanRankData); + logToConsole(LOG_VERBOSE, `[VRR.Clan]: Clan rank '${tempClanRankData.name}' loaded from database successfully!`); + } } freeDatabaseQuery(dbQuery); } @@ -104,29 +103,79 @@ function loadClanRanksFromDatabase(clanDatabaseId) { // =========================================================================== -function loadClanMembersFromDatabase(clanDatabaseId) { - logToConsole(LOG_INFO, `[VRR.Clan]: Loading members for clan ${clanDatabaseId} from database ...`); +function createClanRank(clanId, rankId, rankName) { + let tempClanRankData = new serverClasses.clanRankData(false); + tempClanRankData.level = rankId; + tempClanRankData.name = rankName; + tempClanRankData.clan = getClanData(clanId).databaseId; + tempClanRankData.clanIndex = clanId; + tempClanRankData.needsSaved = true; - let dbConnection = connectToDatabase(); - let dbAssoc; - let tempClanMembers = []; + let rankIndex = getClanData(clanId).ranks.push(tempClanRankData); + setAllClanDataIndexes(); - if(dbConnection) { - let dbQuery = queryDatabase(dbConnection, `SELECT * FROM clan_member WHERE clan_member_clan = ${clanDatabaseId}`); - if(dbQuery) { - if(dbQuery.numRows > 0) { - let dbAssoc = fetchQueryAssoc(dbQuery) - let tempClanMemberData = new serverClasses.clanMemberData(dbAssoc); - tempClanMembers.push(tempClanMemberData); - logToConsole(LOG_VERBOSE, `[VRR.Clan]: Clan member '${tempClanMemberData.subAccount}' loaded from database successfully!`); - } - freeDatabaseQuery(dbQuery); - } - disconnectFromDatabase(dbConnection); + saveAllClanRanksToDatabase(clanId); + return rankIndex; +} + +// =========================================================================== + +function removeClanRank(clanId, rankId) { + let tempClanRankData = getClanRankData(clanId, rankId); + if(!tempClanRankData) { + return false; } - logToConsole(LOG_INFO, `[VRR.Clan]: Loaded members for clan ${clanDatabaseId} from database successfully!`); - return tempClanMembers; + quickDatabaseQuery(`DELETE FROM clan_rank WHERE clan_rank_id = ${tempClanRankData.database}`); + getClanData(clanId).ranks.splice(tempClanRankData.index, 1); +} + +// =========================================================================== + +function listClansCommand(command, params, client) { + let clans = getServerData().clans; + + if(!areParamsEmpty(params)) { + clans = clans.filter(clan => toLowerCase(clan.name).indexOf(toLowerCase(params)) != -1); + return false; + } + + let nameList = clans.map((clan) => { return clan.name; }); + + let chunkedList = splitArrayIntoChunks(nameList, 5); + + messagePlayerInfo(client, `${getInlineChatColourByType("clanOrange")}== ${getInlineChatColourByType("jobYellow")}Clans ${getInlineChatColourByType("clanOrange")}====================================`); + + for(let i in chunkedList) { + messagePlayerInfo(client, chunkedList[i].join(", ")); + } +} + +// =========================================================================== + +function listClanRanksCommand(command, params, client) { + let clanId = getPlayerClan(client); + + if(!areParamsEmpty(params)) { + if(doesPlayerHaveStaffPermission(client, "manageClans")) { + clanId = getClanFromParams(params); + } + } + + if(!getClanData(clanId)) { + messagePlayerError(client, "Clan not found!"); + return false; + } + + let rankNameList = getClanData(clanId).ranks.map((clanRank) => { return `[${clanRank.level}] ${clanRank.name}`; }); + + let chunkedList = splitArrayIntoChunks(rankNameList, 5); + + messagePlayerInfo(client, `${getInlineChatColourByType("clanOrange")}== ${getInlineChatColourByType("jobYellow")}Clan Ranks (${getClanData(clanId).name}) ${getInlineChatColourByType("clanOrange")}=====================`); + + for(let i in chunkedList) { + messagePlayerInfo(client, chunkedList[i].join(", ")); + } } // =========================================================================== @@ -194,6 +243,7 @@ function setClanOwnerCommand(command, params, client) { } getClanData(clanId).owner = getPlayerCurrentSubAccount(targetClient).databaseId; + getPlayerCurrentSubAccount(targetClient).clan = getClanData(clanId).databaseId; getPlayerCurrentSubAccount(targetClient).clanFlags = getClanFlagValue("all"); messageAdmins(`${getInlineChatColourByName("lightGrey")}${getPlayerName(client)} ${getInlineChatColourByName("white")}set clan ${getInlineChatColourByType("clanOrange")}${getClanData(clanId).name} ${getInlineChatColourByName("white")}owner to ${getInlineChatColourByName("lightGrey")}${getCharacterFullName(targetClient)}`); @@ -251,6 +301,69 @@ function setClanNameCommand(command, params, client) { // =========================================================================== +function createClanRankCommand(command, params, client) { + if(!doesPlayerHaveClanPermission(client, getClanFlagValue("manageRanks"))) { + messagePlayerError(client, "You can not add new clan ranks!"); + return false; + } + + if(areParamsEmpty(params)) { + messagePlayerSyntax(client, getCommandSyntaxText(command)); + return false; + } + + let clanId = getPlayerClan(client); + + if(!getClanData(clanId)) { + messagePlayerError(client, "Clan not found!"); + return false; + } + + let splitParams = params.split(" "); + let rankId = toInteger(splitParams[0]); + let rankName = splitParams[1]; + + let rankIndex = createClanRank(clanId, rankId, rankName); + + messagePlayerSuccess(client, `You added the ${getInlineChatColourByName("lightGrey")}${rankName} ${getInlineChatColourByName("white")}rank (Level ${getInlineChatColourByName("lightGrey")}${rankId}`); + messagePlayerSuccess(client, `Use ${getInlineChatColourByName("lightGrey")}/addclanrankflag ${rankName} ${getInlineChatColourByName("white")} to add permission flags to this rank.`); +} + +// =========================================================================== + +function deleteClanRankCommand(command, params, client) { + if(!doesPlayerHaveClanPermission(client, getClanFlagValue("manageRanks"))) { + messagePlayerError(client, "You can not remove clan ranks!"); + return false; + } + + if(areParamsEmpty(params)) { + messagePlayerSyntax(client, getCommandSyntaxText(command)); + return false; + } + + let clanId = getPlayerClan(client); + + if(!getClanData(clanId)) { + messagePlayerError(client, "Clan not found!"); + return false; + } + + let rankId = getClanRankFromParams(clanId, params); + let tempRankName = getClanRankData(clanId, rankId); + + if(!getClanRankData(clanId, rankId)) { + messagePlayerError(client, "Clan rank not found!"); + return false; + } + + removeClanRank(clanId, rankId); + + messagePlayerSuccess(client, `You removed the ${getInlineChatColourByName("lightGrey")}${tempRankName} ${getInlineChatColourByName("white")}rank`); +} + +// =========================================================================== + function setClanMemberTagCommand(command, params, client) { if(!doesPlayerHaveClanPermission(client, getClanFlagValue("memberTag"))) { messagePlayerError(client, "You can not change a clan member's tag!"); @@ -264,22 +377,35 @@ function setClanMemberTagCommand(command, params, client) { let splitParams = params.split(" "); let targetClient = getPlayerFromParams(splitParams[0]); - let tag = splitParams[1] || ""; if(!targetClient) { messagePlayerError(client, "Player not found!"); return false; } - if(!arePlayersInSameClan(client, targetClient) && !doesPlayerHaveStaffPermission(client, getStaffFlagValue("manageClans"))) { - messagePlayerError(client, `${getCharacterFullName(targetClient)} is not in your clan!`); + if(!arePlayersInSameClan(client, targetClient)) { + if(!doesPlayerHaveStaffPermission("manageClans")) { + messagePlayerError(client, "That player is not in your clan!"); + return false; + } + } + + if(!doesPlayerHaveStaffPermission("manageClans") && !doesPlayerHaveClanPermission("memberFlags")) { + messagePlayerError(client, "You cannot set clan member flags!"); return false; } - getPlayerCurrentSubAccount(targetClient).clanTag = tag; + if(getPlayerClanRank(client) <= getPlayerClanRank(targetClient)) { + if(!doesPlayerHaveStaffPermission("manageClans")) { + messagePlayerError(client, "You cannot set that clan member's flags!"); + return false; + } + } - messagePlayerSuccess(client, `You set ${getInlineChatColourByName("lightGrey")}${getCharacterFullName(targetClient)}'s ${getInlineChatColourByName("white")}clan tag to ${getInlineChatColourByName("lightGrey")}${tag}`); - messagePlayerAlert(client, `${getInlineChatColourByName("lightGrey")}${getCharacterFullName(targetClient)} ${getInlineChatColourByName("white")}set your clan tag to ${getInlineChatColourByName("lightGrey")}${tag}`); + getPlayerCurrentSubAccount(targetClient).clanTag = splitParams[1]; + + messagePlayerSuccess(client, `You set ${getInlineChatColourByName("lightGrey")}${getCharacterFullName(targetClient)}'s ${getInlineChatColourByName("white")}clan tag to ${getInlineChatColourByName("lightGrey")}${splitParams[1]}`); + messagePlayerAlert(client, `${getInlineChatColourByName("lightGrey")}${getCharacterFullName(targetClient)} ${getInlineChatColourByName("white")}set your clan tag to ${getInlineChatColourByName("lightGrey")}${splitParams[1]}`); } // =========================================================================== @@ -296,7 +422,6 @@ function setClanRankTagCommand(command, params, client) { } let splitParams = params.split(" "); - let clanId = getPlayerClan(client); if(!getClanData(clanId)) { @@ -332,18 +457,33 @@ function addClanMemberFlagCommand(command, params, client) { return false; } + let splitParams = params.split(" "); let targetClient = getPlayerFromParams(splitParams[0]); if(!targetClient) { - messagePlayerError(client, "Clan member not found!"); + messagePlayerError(client, "Player not found!"); return false; } - if(!getClanFlagValue(splitParams[1])) { - messagePlayerError(client, "Clan flag not found!"); + if(!arePlayersInSameClan(client, targetClient)) { + if(!doesPlayerHaveStaffPermission("manageClans")) { + messagePlayerError(client, "That player is not in your clan!"); + return false; + } + } + + if(!doesPlayerHaveStaffPermission("manageClans") && !doesPlayerHaveClanPermission("memberFlags")) { + messagePlayerError(client, "You cannot set clan member flags!"); return false; } + if(getPlayerClanRank(client) <= getPlayerClanRank(targetClient)) { + if(!doesPlayerHaveStaffPermission("manageClans")) { + messagePlayerError(client, "You cannot set that clan member's flags!"); + return false; + } + } + let flagValue = getClanFlagValue(splitParams[1]); getPlayerCurrentSubAccount(client).clanFlags = getPlayerCurrentSubAccount(client).clanFlags | flagValue; messagePlayerSuccess(client, `You added the ${getInlineChatColourByName("lightGrey")}${splitParams[1]} ${getInlineChatColourByName("white")}clan flag to ${getInlineChatColourByName("lightGrey")}${getCharacterFullName(client)}`); @@ -369,18 +509,33 @@ function removeClanMemberFlagCommand(command, params, client) { return false; } + let splitParams = params.split(" "); let targetClient = getPlayerFromParams(splitParams[0]); if(!targetClient) { - messagePlayerError(client, "Clan member not found!"); + messagePlayerError(client, "Player not found!"); return false; } - if(!getClanFlagValue(splitParams[1])) { - messagePlayerError(client, "Clan flag not found!"); + if(!arePlayersInSameClan(client, targetClient)) { + if(!doesPlayerHaveStaffPermission("manageClans")) { + messagePlayerError(client, "That player is not in your clan!"); + return false; + } + } + + if(!doesPlayerHaveStaffPermission("manageClans") && !doesPlayerHaveClanPermission("memberFlags")) { + messagePlayerError(client, "You cannot set clan member flags!"); return false; } + if(getPlayerClanRank(client) <= getPlayerClanRank(targetClient)) { + if(!doesPlayerHaveStaffPermission("manageClans")) { + messagePlayerError(client, "You cannot set that clan member's flags!"); + return false; + } + } + let flagValue = getClanFlagValue(splitParams[1]); getPlayerCurrentSubAccount(client).clanFlags = getPlayerCurrentSubAccount(client).clanFlags & ~flagValue; messagePlayerSuccess(client, `You removed the ${getInlineChatColourByName("lightGrey")}${splitParams[1]} ${getInlineChatColourByName("white")}clan flag from ${getInlineChatColourByName("lightGrey")}${getCharacterFullName(client)}`); @@ -406,6 +561,7 @@ function addClanRankFlagCommand(command, params, client) { return false; } + let splitParams = params.split(" "); let rankId = getClanRankFromParams(clanId, splitParams[0]); if(!getClanRankData(clanId, rankId)) { @@ -444,6 +600,7 @@ function removeClanRankFlagCommand(command, params, client) { return false; } + let splitParams = params.split(" "); let rankId = getClanRankFromParams(clanId, splitParams[0]); if(!getClanRankData(clanId, rankId)) { @@ -482,15 +639,30 @@ function setClanMemberTitleCommand(command, params, client) { return false; } - let rankId = getClanRankFromParams(clanId); + let splitParams = params.split(" "); + let targetClient = getPlayerFromParams(splitParams[0]); - if(!getClanRankData(clanId, rankId)) { - messagePlayerError(client, "Clan rank not found!"); + if(!targetClient) { + messagePlayerError(client, "Player not found!"); return false; } + if(!arePlayersInSameClan(client, targetClient)) { + if(!doesPlayerHaveStaffPermission(client, "manageClans")) { + messagePlayerError(client, "That player is not in your clan!"); + return false; + } + } + + if(getPlayerClanRank(client) <= getPlayerClanRank(targetClient)) { + if(!doesPlayerHaveStaffPermission(client, "manageClans")) { + messagePlayerError(client, "You cannot set that clan member's custom title!"); + return false; + } + } + let oldMemberTitle = getPlayerCurrentSubAccount(client).clanTitle; - getPlayerCurrentSubAccount(client).clanTitle = params; + getPlayerCurrentSubAccount(client).clanTitle = splitParams[1]; messagePlayerSuccess(client, `You changed the name of ${getInlineChatColourByName("lightGrey")}${getCharacterFullName(client)} ${getInlineChatColourByName("white")}from ${getInlineChatColourByName("lightGrey")}${oldMemberTitle} ${getInlineChatColourByName("white")}to ${getInlineChatColourByName("lightGrey")}${params}`); } @@ -514,7 +686,8 @@ function setClanRankTitleCommand(command, params, client) { return false; } - let rankId = getClanRankFromParams(clanId); + let splitParams = params.split(" "); + let rankId = getClanRankFromParams(clanId, splitParams[0]); if(!getClanRankData(clanId, rankId)) { messagePlayerError(client, "Clan rank not found!"); @@ -522,12 +695,73 @@ function setClanRankTitleCommand(command, params, client) { } let oldRankName = getClanRankData(clanId, rankId).name; - getClanRankData(clanId, rankId).name = params; + getClanRankData(clanId, rankId).name = splitParams[1]; messagePlayerSuccess(client, `You changed the name of rank ${rankId} from ${getInlineChatColourByName("lightGrey")}${oldRankName} ${getInlineChatColourByName("white")}to ${getInlineChatColourByName("lightGrey")}${params}`); } // =========================================================================== +function setClanMemberRankCommand(command, params, client) { + if(!doesPlayerHaveClanPermission(client, getClanFlagValue("memberRank"))) { + messagePlayerError(client, "You can not change a clan member's rank!"); + return false; + } + + if(areParamsEmpty(params)) { + messagePlayerSyntax(client, getCommandSyntaxText(command)); + return false; + } + + let clanId = getPlayerClan(client); + + if(!getClanData(clanId)) { + messagePlayerError(client, "Clan not found!"); + return false; + } + + let splitParams = params.split(" "); + let targetClient = getPlayerFromParams(splitParams[0]); + let rankId = getClanRankFromParams(clanId, splitParams[1]); + + if(!targetClient) { + messagePlayerError(client, "Player not found!"); + return false; + } + + if(!getClanRankData(clanId, rankId)) { + messagePlayerError(client, "Clan rank not found!"); + return false; + } + + if(!arePlayersInSameClan(client, targetClient)) { + if(!doesPlayerHaveStaffPermission(client, "manageClans")) { + messagePlayerError(client, "That player is not in your clan!"); + return false; + } + } + + if(getPlayerClanRank(client) <= getPlayerClanRank(targetClient)) { + if(!doesPlayerHaveStaffPermission(client, "manageClans")) { + messagePlayerError(client, "You cannot set that clan member's rank!"); + return false; + } + } + + if(getPlayerClanRank(client) <= getPlayerClanRank(targetClient)) { + if(!doesPlayerHaveStaffPermission(client, "manageClans")) { + messagePlayerError(client, "You can't set a member's rank that high!"); + return false; + } + } + + let oldClanRank = getClanRankData(clanId, getPlayerClanRank(targetClient)); + getPlayerCurrentSubAccount(targetClient).clanRank = getClanRankData(clanId, rankId).databaseId; + getPlayerCurrentSubAccount(targetClient).clanRankIndex = rankId; + messagePlayerSuccess(client, `You changed ${getInlineChatColourByName("lightGrey")}${getCharacterFullName(targetClient)}'s ${getInlineChatColourByName("white")}rank from ${getInlineChatColourByName("lightGrey")}${oldClanRank.name} ${getInlineChatColourByName("white")}to ${getInlineChatColourByName("lightGrey")}${getClanRankData(clanId, rankId).name}`); +} + +// =========================================================================== + function createClan(name) { let dbConnection = connectToDatabase(); let escapedName = name; @@ -536,6 +770,7 @@ function createClan(name) { escapedName = escapeDatabaseString(dbConnection, escapedName) queryDatabase(dbConnection, `INSERT INTO clan_main (clan_server, clan_name) VALUES (${getServerId()}, '${escapedName}')`); + let tempClan = new serverClasses.clanData(false); tempClan.databaseId = getDatabaseInsertId(dbConnection); tempClan.name = name; getServerData().clans.push(tempClan); @@ -609,7 +844,7 @@ function reloadAllClans() { function saveAllClanRanksToDatabase(clanId) { let ranks = getServerData().clans[clanId].ranks; for(let i in ranks) { - saveClanRankToDatabase(ranks[i]); + saveClanRankToDatabase(clanId, i); } } @@ -661,7 +896,7 @@ function saveClanToDatabase(clanId) { // =========================================================================== -function saveClanRankToDatabase(clanData, rankId) { +function saveClanRankToDatabase(clanId, rankId) { let tempClanRankData = getClanRankData(clanId, rankId); let dbConnection = connectToDatabase(); @@ -669,13 +904,13 @@ function saveClanRankToDatabase(clanData, rankId) { if(tempClanRankData.needsSaved) { let safeName = escapeDatabaseString(dbConnection, tempClanRankData.name); let safeTag = escapeDatabaseString(dbConnection, tempClanRankData.customTag); - let safeTitle = escapeDatabaseString(dbConnection, tempClanRankData.customTitle); + //let safeTitle = escapeDatabaseString(dbConnection, tempClanRankData.name); let data = [ ["clan_rank_name", safeName], - ["clan_rank_clan", tempClanRankData.clanId], - ["clan_rank_tag", safeTag], - ["clan_rank_title", safeTitle], + ["clan_rank_clan", tempClanRankData.clan], + ["clan_rank_custom_tag", safeTag], + //["clan_rank_title", safeTitle], ["clan_rank_flags", tempClanRankData.flags], ["clan_rank_level", tempClanRankData.level], ["clan_rank_enabled", boolToInt(tempClanRankData.enabled)], @@ -683,12 +918,12 @@ function saveClanRankToDatabase(clanData, rankId) { let dbQuery = null; if(tempClanRankData.databaseId == 0) { - let queryString = createDatabaseInsertQuery("clan_main", data); + let queryString = createDatabaseInsertQuery("clan_rank", data); dbQuery = queryDatabase(dbConnection, queryString); getClanRankData(clanId, rankId).databaseId = getDatabaseInsertId(dbConnection); getClanRankData(clanId, rankId).needsSaved = false; } else { - let queryString = createDatabaseUpdateQuery("clan_rank_main", data, `clan_rank_id=${tempClanRankData.databaseId} LIMIT 1`); + let queryString = createDatabaseUpdateQuery("clan_rank", data, `clan_rank_id=${tempClanRankData.databaseId} LIMIT 1`); dbQuery = queryDatabase(dbConnection, queryString); getClanRankData(clanId, rankId).needsSaved = false; } @@ -775,4 +1010,53 @@ function getPlayerClanRank(client) { return getPlayerCurrentSubAccount(client).clanRank; } +// =========================================================================== + +function getPlayerClan(client) { + return getClanIdFromDatabaseId(getPlayerCurrentSubAccount(client).clan); +} + +// =========================================================================== + +function getClanIdFromDatabaseId(databaseId) { + for(let i in getServerData().clans) { + if(getServerData().clans[i].databaseId == databaseId) { + return i; + } + } +} + +// =========================================================================== + +function getClanRankIdFromDatabaseId(clanId, databaseId) { + for(let i in getServerData().clans[clanId].ranks) { + if(getServerData().clans[clanId].ranks[i].databaseId == databaseId) { + return i; + } + } +} + +// =========================================================================== + +function getClanRankData(clanId, rankId) { + return getServerData().clans[clanId].ranks[rankId]; +} + +// =========================================================================== + +function getPlayerSubAccountClanRank(client) { + return getPlayerCurrentSubAccount(client).clanRank; +} + +// =========================================================================== + +function getPlayerClanRankName(client) { + if(getPlayerClanRank(client) != 0) { + let clanId = getPlayerClan(client); + return getClanRankData(clanId, getClanRankIdFromDatabaseId(clanId, getPlayerCurrentSubAccount(client).clanRank)).name; + } else { + return false; + } +} + // =========================================================================== \ No newline at end of file diff --git a/scripts/server/class.js b/scripts/server/class.js index 84944247..b55d8a96 100644 --- a/scripts/server/class.js +++ b/scripts/server/class.js @@ -32,6 +32,8 @@ function initClassTable() { this.newCharacter = { spawnPosition: false, spawnHeading: 0.0, + spawnInterior: 0, + spawnDimension: 0, money: 0, bank: 0, skin: 0, @@ -81,6 +83,9 @@ function initClassTable() { this.pauseSavingToDatabase = false; + this.useRealTime = false; + this.realTimeZone = 0; + if(dbAssoc) { this.databaseId = dbAssoc["svr_id"]; console.log("1"); @@ -133,6 +138,8 @@ function initClassTable() { this.createHouseBlips = intToBool(dbAssoc["svr_house_blips"]); this.introMusicURL = dbAssoc["svr_intro_music"]; + this.useRealTime = intToBool(dbAssoc["svr_time_realtime_enabled"]); + this.realTimeZone = dbAssoc["svr_time_realtime_timezone"]; } } }, @@ -734,8 +741,8 @@ function initClassTable() { this.name = ""; this.level = 0; this.flags = 0; - this.tag = ""; - this.enabled = false; + this.customTag = ""; + this.enabled = true; this.index = -1; this.clanIndex = -1; this.needsSaved = false; diff --git a/scripts/server/colour.js b/scripts/server/colour.js index 5acd8bb6..98656ea9 100644 --- a/scripts/server/colour.js +++ b/scripts/server/colour.js @@ -160,12 +160,26 @@ function getPlayerColour(client) { // =========================================================================== -function getBoolRedGreenInlineColour(boolVal) { - return (!boolVal) ? "[#CD3C3C]" : "[#32CD32]"; +/** + * Gets the red/green colour depending on bool (red = false, green = true) for inline use in chatbox messages + * + * @param {Boolean} boolValue The boolean value + * @return {String} Red or green inline HEX colour string + * + */ +function getBoolRedGreenInlineColour(boolValue) { + return (!boolValue) ? "[#CD3C3C]" : "[#32CD32]"; } // =========================================================================== +/** + * Gets an array of RGB colour values from a HEX colour string + * + * @param {String} hexColour Hex colour string + * @return {Array} 3-slot array where each slot is an RGB colour value + * + */ function hexToRgb(h) { return [ '0x'+h[1]+h[2]|0, @@ -176,12 +190,28 @@ function hexToRgb(h) { // =========================================================================== +/** + * Gets a HEX colour string from RGB values, without brackets (example: #FFFFFF) + * + * @param {Number} red Red RGB value + * @param {Number} green Green RGB value + * @param {Number} blue Blue RGB value + * @return {String} HEX colour string + * + */ function rgbToHex(r, g, b) { return "#"+((1<<24)+(r<<16)+(g<<8)+ b).toString(16).slice(1); } // =========================================================================== +/** + * Gets the current colour for a player (affected by job and status) + * + * @param {Client} client Player client + * @return {Number} Colour integer + * + */ function getClientChatColour(client) { let tempJob = getPlayerCurrentSubAccount(client).job; if(tempJob != -1) { @@ -194,6 +224,12 @@ function getClientChatColour(client) { // =========================================================================== +/** + * Gets a toColour-created colour integer with random RGB values (alpha is always 255) + * + * @return {Number} Colour integer + * + */ function getRandomRGB() { return toColour.apply(null, [ getRandom(0, 255), @@ -205,18 +241,39 @@ function getRandomRGB() { // =========================================================================== +/** + * Gets a hex formatting colour by name for use inline in chatbox messages (example: [#FFFFFF]). + * + * @param {String} colourName - Colour name + * @return {String} HEX-formatted colour string with brackets + * + */ function getInlineChatColourByName(colourName) { return `[${getHexColourByName(colourName)}]`; } // =========================================================================== +/** + * Gets a hex formatting colour by type for use inline in chatbox messages (example: [#FFFFFF]). + * + * @param {String} colourName - Colour type + * @return {String} HEX-formatted colour string with brackets + * + */ function getInlineChatColourByType(colourName) { return `[${getHexColourByType(colourName)}]`; } // =========================================================================== +/** + * Gets an array of RGBA colour values from a toColour integer. + * + * @param {Number} colour - Colour integer created by toColour + * @return {Array} 4-slot array where each slot is an RGBA colour value + * + */ function rgbaArrayFromToColour(colour) { //return [ // (colour >> 24) & 0xFF, // red diff --git a/scripts/server/command.js b/scripts/server/command.js index f91d8afd..3caa7ca9 100644 --- a/scripts/server/command.js +++ b/scripts/server/command.js @@ -126,9 +126,17 @@ function loadCommands() { commandData("achat", adminChatCommand, "", getStaffFlagValue("basicModeration"), true, true, "Sends an OOC chat message to other admins"), ], clan: [ + commandData("clans", listClansCommand, "[search text]", getStaffFlagValue("none"), true, true, "List clans (search by partial name, if provided)"), + commandData("clanranks", listClanRanksCommand, "[clan name]", getStaffFlagValue("none"), true, true, "Shows a list of a clan's ranks"), + commandData("addclan", createClanCommand, "", getStaffFlagValue("manageClans"), true, true, "Creates an new empty, unowned clan."), commandData("delclan", deleteClanCommand, "", getStaffFlagValue("manageClans"), true, true, "Deletes a clan by ID or name"), + commandData("addclanrank", createClanRankCommand, " ", getStaffFlagValue("none"), true, true, "Adds a clan rank"), + commandData("delclanrank", deleteClanRankCommand, "", getStaffFlagValue("none"), true, true, "Removes a clan rank"), + + commandData("setclanrank", setClanMemberRankCommand, " ", getStaffFlagValue("none"), true, true, "Sets the rank of a clan member"), + commandData("clanowner", setClanOwnerCommand, " ", getStaffFlagValue("none"), true, true, "Gives ownership of the clan to a player"), commandData("clantag", setClanTagCommand, "", getStaffFlagValue("none"), true, true, "Sets a clan's main tag"), commandData("clanranktag", setClanRankTagCommand, " ", getStaffFlagValue("none"), true, true, "Sets a clan rank's custom tag"), @@ -156,7 +164,7 @@ function loadCommands() { commandData("setsnow", setSnowingCommand, " ", getStaffFlagValue("manageServer"), true, true, "Toggles winter/snow"), commandData("setlogo", toggleServerLogoCommand, "<0/1 state>", getStaffFlagValue("manageServer"), true, true, "Toggles the corner server logo display on/off"), commandData("setgui", toggleServerGUICommand, "<0/1 state>", getStaffFlagValue("manageServer"), true, true, "Toggles server GUI on/off"), - //commandData("setguicolours", setServerGUIColoursCommand, " ", getStaffFlagValue("manageServer"), true, true), + commandData("setguicolours", setServerGUIColoursCommand, " ", getStaffFlagValue("manageServer"), true, true), commandData("newcharspawn", setNewCharacterSpawnPositionCommand, "", getStaffFlagValue("manageServer"), true, true, "Sets the starting spawn position for new characters"), commandData("newcharcash", setNewCharacterMoneyCommand, "", getStaffFlagValue("manageServer"), true, true, "Sets the starting money for new characters"), commandData("newcharskin", setNewCharacterSkinCommand, "[skin id]", getStaffFlagValue("manageServer"), true, true, "Sets the default skin for new characters"), @@ -307,12 +315,14 @@ function loadCommands() { commandData("unfreeze", unFreezeClientCommand, " [reason]", getStaffFlagValue("basicModeration"), true, true, "Unfreezes a player, allowing them to move again."), commandData("goto", gotoPlayerCommand, "", getStaffFlagValue("basicModeration"), true, true, "Teleports you to a player."), commandData("gethere", getPlayerCommand, "", getStaffFlagValue("basicModeration"), true, true, "Teleports a player to you."), + commandData("returnplr", returnPlayerCommand, "", getStaffFlagValue("basicModeration"), true, true, "Returns a player to their previous position."), commandData("gotopos", gotoPositionCommand, " [int] [vw]", getStaffFlagValue("basicModeration"), true, true, "Teleports you to specific coordinates with optional interior and dimension."), commandData("gotoveh", gotoVehicleCommand, "", getStaffFlagValue("basicModeration"), true, true, "Teleports you to a vehicle by ID."), commandData("gotobiz", gotoBusinessCommand, "", getStaffFlagValue("basicModeration"), true, true, "Teleports you to a business by ID or name."), commandData("gotohouse", gotoHouseCommand, "", getStaffFlagValue("basicModeration"), true, true, "Teleports you to a house by ID or description."), commandData("gotojob", gotoJobLocationCommand, " ", getStaffFlagValue("basicModeration"), true, true, "Teleports you to a job location by name and location ID."), commandData("gotoloc", gotoGameLocationCommand, "", getStaffFlagValue("basicModeration"), true, true, "Teleports you to a game location by name."), + commandData("gotospawn", gotoNewPlayerSpawnCommand, "", getStaffFlagValue("basicModeration"), true, true, "Teleports you to the new player spawn location"), commandData("fr", teleportForwardCommand, "", getStaffFlagValue("basicModeration"), true, true, "Teleports you forward a certain distance in meters."), commandData("ba", teleportBackwardCommand, "", getStaffFlagValue("basicModeration"), true, true, "Teleports you backward a certain distance in meters."), commandData("lt", teleportLeftCommand, "", getStaffFlagValue("basicModeration"), true, true, "Teleports you to the left a certain distance in meters."), @@ -321,24 +331,22 @@ function loadCommands() { commandData("dn", teleportDownCommand, "", getStaffFlagValue("basicModeration"), true, true, "Teleports you downward a certain distance in meters."), commandData("int", playerInteriorCommand, "", getStaffFlagValue("basicModeration"), true, true, "Gets or sets a player's game interior."), commandData("vw", playerVirtualWorldCommand, "", getStaffFlagValue("basicModeration"), true, true, "Gets or sets a player's virtual world/dimension."), - commandData("addstaffflag", addStaffFlagCommand, " ", getStaffFlagValue("manageAdmins"), true, true, "Gives a player a staff flaf (this server only)."), commandData("delstaffflag", takeStaffFlagCommand, " ", getStaffFlagValue("manageAdmins"), true, true, "Takes a player's staff flag by name (this server only)."), commandData("getstaffflags", getStaffFlagsCommand, "", getStaffFlagValue("manageAdmins"), true, true, "Shows a list of all staff flags a player has (this server only)."), commandData("clearstaffflags", clearStaffFlagsCommand, "", getStaffFlagValue("manageAdmins"), true, true, "Removes all staff flags for a player (this server only)."), commandData("staffflags", allStaffFlagsCommand, "", getStaffFlagValue("manageAdmins"), true, true, "Shows a list of all valid staff flag names."), - commandData("givemoney", givePlayerMoneyCommand, " ", getStaffFlagValue("serverManager"), true, true), - commandData("nonrpname", forceCharacterNameChangeCommand, "", getStaffFlagValue("basicModeration"), true, true, "Forces a player to change their current character's name."), commandData("forcename", forceCharacterNameCommand, " ", getStaffFlagValue("basicModeration"), true, true, "Changes a character's name directly."), - commandData("forceskin", forcePlayerSkinCommand, " ", getStaffFlagValue("basicModeration"), true, true, "Changes a character's skin directly."), - commandData("plrinfo", getPlayerInfoCommand, "", getStaffFlagValue("basicModeration"), true, true, "Shows basic info about the specified player"), commandData("getplrhouse", getAllHousesOwnedByPlayerCommand, "", getStaffFlagValue("basicModeration"), true, true, "Shows a list of all houses owned by the player"), commandData("getplrbiz", getAllBusinessesOwnedByPlayerCommand, "", getStaffFlagValue("basicModeration"), true, true, "Shows a list of all businesses owned by the player"), commandData("getplrveh", getAllVehiclesOwnedByPlayerCommand, "", getStaffFlagValue("basicModeration"), true, true, "Shows a list of all vehicles owned by the player"), + commandData("geoip", getGeoIPInformationCommand, "", getStaffFlagValue("basicModeration"), true, true, "Retrieves GeoIP information on a player (country & city)"), + + commandData("forcepayday", forcePlayerPayDayCommand, "", getStaffFlagValue("manageServer"), true, true, "Gives a player an instant payday."), ], radio: [ commandData("radiostation", playStreamingRadioCommand, "", getStaffFlagValue("none"), true, false, "Plays a radio station in your vehicle, house, or business (depending on which one you're in)"), diff --git a/scripts/server/config.js b/scripts/server/config.js index af6c3ceb..11ceed45 100644 --- a/scripts/server/config.js +++ b/scripts/server/config.js @@ -56,6 +56,8 @@ function loadGlobalConfig() { subAccountNameAllowedCharacters: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", emailValidationRegex: /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/, itemActionDelayExtraTimeout: 1000, + geoIPCountryDatabaseFilePath: "geoip-country.mmdb", + geoIPCityDatabaseFilePath: "geoip-city.mmdb", }; } @@ -151,9 +153,9 @@ function saveServerConfigToDatabase(serverConfigData) { ["svr_newchar_rot_z", serverConfigData.newCharacter.spawnHeading], ["svr_newchar_skin", serverConfigData.newCharacter.skin], ["svr_newchar_money", serverConfigData.newCharacter.money], - ["svr_gui_r", serverConfigData.guiColour[0]], - ["svr_gui_g", serverConfigData.guiColour[1]], - ["svr_gui_b", serverConfigData.guiColour[2]], + ["svr_gui_col1_r", serverConfigData.guiColour[0]], + ["svr_gui_col1_g", serverConfigData.guiColour[1]], + ["svr_gui_col1_b", serverConfigData.guiColour[2]], ["svr_connectcam_pos_x", serverConfigData.connectCameraPosition.x], ["svr_connectcam_pos_y", serverConfigData.connectCameraPosition.y], ["svr_connectcam_pos_z", serverConfigData.connectCameraPosition.z], @@ -225,6 +227,15 @@ function getServerId() { // =========================================================================== +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ function setTimeCommand(command, params, client) { if(areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); @@ -262,6 +273,15 @@ function setTimeCommand(command, params, client) { // =========================================================================== +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ function setMinuteDurationCommand(command, params, client) { if(areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); @@ -280,6 +300,15 @@ function setMinuteDurationCommand(command, params, client) { // =========================================================================== +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ function setWeatherCommand(command, params, client) { if(areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); @@ -306,6 +335,15 @@ function setWeatherCommand(command, params, client) { // =========================================================================== +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ function setSnowingCommand(command, params, client) { if(areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); @@ -330,6 +368,51 @@ function setSnowingCommand(command, params, client) { // =========================================================================== +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ +function setServerGUIColoursCommand(command, params, client) { + if(areParamsEmpty(params)) { + messagePlayerSyntax(client, getCommandSyntaxText(command)); + return false; + } + + let splitParams = params.split(); + let colourRed = toInteger(splitParams[0]) || 255; + let colourGreen = toInteger(splitParams[1]) || 255; + let colourBlue = toInteger(splitParams[2]) || 255; + + getServerConfig().guiColour = [colourRed, colourGreen, colourBlue]; + + let clients = getClients(); + for(let i in clients) { + sendPlayerGUIColours(clients[i]); + } + + getServerConfig().needsSaved = true; + + //messageAdminAction(`${getPlayerName(client)} ${getInlineChatColourByName("orange")}set the server ${getBoolRedGreenInlineColour(fallingSnow)}${getOnOffFromBool(fallingSnow)} ${getInlineChatColourByName("orange")}and ground snow ${getBoolRedGreenInlineColour(groundSnow)}${getOnOffFromBool(groundSnow)}`); + //updateServerRules(); + return true; +} + +// =========================================================================== + +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ function toggleServerLogoCommand(command, params, client) { getServerConfig().useLogo = !getServerConfig().useLogo; @@ -342,6 +425,15 @@ function toggleServerLogoCommand(command, params, client) { // =========================================================================== +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ function toggleAntiCheatScriptWhitelist(command, params, client) { getServerConfig().antiCheat.gameScriptWhiteListEnabled = !getServerConfig().antiCheat.gameScriptWhiteListEnabled; getServerConfig().needsSaved = true; @@ -353,6 +445,15 @@ function toggleAntiCheatScriptWhitelist(command, params, client) { // =========================================================================== +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ function toggleAntiCheatScriptBlacklist(command, params, client) { getServerConfig().antiCheat.gameScriptBlackListEnabled = !getServerConfig().antiCheat.gameScriptBlackListEnabled; getServerConfig().needsSaved = true; @@ -364,6 +465,15 @@ function toggleAntiCheatScriptBlacklist(command, params, client) { // =========================================================================== +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ function toggleServerGUICommand(command, params, client) { getServerConfig().useGUI = !getServerConfig().useGUI; getServerConfig().needsSaved = true; @@ -375,6 +485,62 @@ function toggleServerGUICommand(command, params, client) { // =========================================================================== +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ +function toggleServerUseRealWorldTimeCommand(command, params, client) { + getServerConfig().useRealTime = !getServerConfig().useRealTime; + getServerConfig().needsSaved = true; + + messageAdminAction(`${getPlayerName(client)} turned real-world time ${toLowerCase(getOnOffFromBool(getServerConfig().useRealTime))} for this server (GMT ${addPositiveNegativeSymbol(getServerConfig().realTimeZone)})`); + updateServerGameTime(); + updateServerRules(); + return true; +} + +// =========================================================================== + +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ +function setServerRealWorldTimeZoneCommand(command, params, client) { + if(areParamsEmpty(params)) { + messagePlayerSyntax(client, getCommandSyntaxText(command)); + return false; + } + + getServerConfig().realTimeZone = toInteger(params); + getServerConfig().needsSaved = true; + + messageAdminAction(`${getPlayerName(client)} set the time zone for in-game's real-world time to GMT ${addPositiveNegativeSymbol(getServerConfig().realTimeZone)}`); + updateServerGameTime(); + updateServerRules(); + return true; +} + +// =========================================================================== + +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ function reloadServerConfigurationCommand(command, params, client) { serverConfig = loadServerConfigFromGameAndPort(server.game, server.port); applyConfigToServer(serverConfig); @@ -387,6 +553,15 @@ function reloadServerConfigurationCommand(command, params, client) { // =========================================================================== +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ function reloadEmailConfigurationCommand(command, params, client) { emailConfig = loadEmailConfiguration(); messageAdminAction(`${getPlayerName(client)} reloaded the email configuration`); @@ -395,6 +570,15 @@ function reloadEmailConfigurationCommand(command, params, client) { // =========================================================================== +/** + * This is a command handler function. + * + * @param {string} command - The command name used by the player + * @param {string} params - The parameters/args string used with the command by the player + * @param {Client} client - The client/player that used the command + * @return {bool} Whether or not the command was successful + * + */ function reloadDatabaseConfigurationCommand(command, params, client) { //if(!databaseInUse) { if(databaseConfig.usePersistentConnection && isDatabaseConnected(persistentDatabaseConnection)) { diff --git a/scripts/server/const.js b/scripts/server/const.js index dfd9e02e..a2653159 100644 --- a/scripts/server/const.js +++ b/scripts/server/const.js @@ -22,6 +22,7 @@ const VRR_JOB_TAXI = 5; const VRR_JOB_GARBAGE = 6; const VRR_JOB_WEAPON = 7; const VRR_JOB_DRUG = 8; +const VRR_JOB_PIZZA = 9; // Pickup Types const VRR_PICKUP_NONE = 0; diff --git a/scripts/server/economy.js b/scripts/server/economy.js index 2d59eefb..f9d0dbcc 100644 --- a/scripts/server/economy.js +++ b/scripts/server/economy.js @@ -39,7 +39,7 @@ function playerPayDay(client) { let netIncome = grossIncome-taxAmount; messagePlayerAlert(client, "== Payday! ============================="); - messagePlayerInfo(client, `Your paycheck: ${getInlineChatColourByName("lightGrey")}$${grossIncome}`); + messagePlayerInfo(client, `Paycheck: ${getInlineChatColourByName("lightGrey")}$${grossIncome}`); messagePlayerInfo(client, `Taxes: ${getInlineChatColourByName("lightGrey")}$${taxAmount}`); messagePlayerInfo(client, `You receive: ${getInlineChatColourByName("lightGrey")}$${netIncome}`); @@ -60,4 +60,22 @@ function calculateTax(client) { return 0; } +// =========================================================================== + +function forcePlayerPayDayCommand(command, params, client) { + if(areParamsEmpty(params)) { + messagePlayerSyntax(client, getCommandSyntaxText(command)); + return false; + } + + let targetClient = getPlayerFromParams(params); + if(!targetClient) { + messagePlayerError(client, "That player is not connected!"); + return false; + } + + messageAdmins(`${client.name} gave ${targetClient.name} an instant payday`); + playerPayDay(targetClient); +} + // =========================================================================== \ No newline at end of file diff --git a/scripts/server/event.js b/scripts/server/event.js index 06c228be..191dd301 100644 --- a/scripts/server/event.js +++ b/scripts/server/event.js @@ -471,7 +471,9 @@ function onPlayerSpawn(client) { if(getServerGame() == GAME_GTA_SA) { logToConsole(LOG_DEBUG, `[VRR.Event] Setting player walk and fightstyle for ${getPlayerDisplayForConsole(client)}`); setEntityData(client.player, "vrr.walkStyle", getPlayerCurrentSubAccount(client).walkStyle, true); - setEntityData(client.player, "vrr.fightStyle", getPlayerCurrentSubAccount(client).fightStyle, true); + + let fightStyleId = getPlayerCurrentSubAccount(client).fightStyle; + setEntityData(client.player, "vrr.fightStyle", [getGameData().fightStyles[getServerGame()][fightStyleId][1][0], getGameData().fightStyles[getServerGame()][fightStyleId][1][1]], true); } logToConsole(LOG_DEBUG, `[VRR.Event] Updating logo state for ${getPlayerDisplayForConsole(client)}`); diff --git a/scripts/server/help.js b/scripts/server/help.js index 52d203c7..6455d3af 100644 --- a/scripts/server/help.js +++ b/scripts/server/help.js @@ -143,6 +143,7 @@ function helpCommand(command, params, client) { // == Command Info ============================= // == Player Vehicles ========================== // == Player Businesses ======================== +// == Clans ==================================== // =========================================================================== diff --git a/scripts/server/house.js b/scripts/server/house.js index 44df5741..e6fc02b0 100644 --- a/scripts/server/house.js +++ b/scripts/server/house.js @@ -82,10 +82,10 @@ function createHouseCommand(command, params, client) { saveHouseToDatabase(houseId-1); - //createHouseEntrancePickup(houseId); - //createHouseExitPickup(houseId); - //createHouseEntranceBlip(houseId); - //createHouseExitBlip(houseId); + createHouseEntrancePickup(houseId); + createHouseExitPickup(houseId); + createHouseEntranceBlip(houseId); + createHouseExitBlip(houseId); //getHouseData(houseId).needsSaved = true; @@ -113,15 +113,16 @@ function lockUnlockHouseCommand(command, params, client) { getHouseData(houseId).locked = !getHouseData(houseId).locked; - for(let i in getHouseData(houseId).locations) { - if(getHouseData(houseId).locations[i].type == VRR_HOUSE_LOC_DOOR) { - setEntityData(getHouseData(houseId).locations[i].entrancePickup, "vrr.label.locked", getHouseData(houseId).locked, true); - } - } + //for(let i in getHouseData(houseId).locations) { + // if(getHouseData(houseId).locations[i].type == VRR_HOUSE_LOC_DOOR) { + // setEntityData(getHouseData(houseId).locations[i].entrancePickup, "vrr.label.locked", getHouseData(houseId).locked, true); + // } + //} + setEntityData(getHouseData(houseId).entrancePickup, "vrr.label.locked", getHouseData(houseId).locked, true); getHouseData(houseId).needsSaved = true; - messagePlayerSuccess(client, `House '${getHouseData(houseId).description}' ${getLockedUnlockedTextFromBool((getHouseData(houseId).locked))}!`); + messagePlayerSuccess(client, `House ${getInlineChatColourByType("houseGreen")}${getHouseData(houseId).description} ${getInlineChatColourByName("white")}${getLockedUnlockedTextFromBool((getHouseData(houseId).locked))}!`); } // =========================================================================== @@ -148,7 +149,7 @@ function lockUnlockHouseCommand(command, params, client) { getHouseData(houseId).needsSaved = true; updateHouseInteriorLightsForOccupants(houseId); - messagePlayerMeAction(client, `turns ${getOnOffFromBool(getHouseData(houseId).interiorLights)} the house lights`); + meActionToNearbyPlayers(client, `turns ${toLowerCase(getOnOffFromBool(getHouseData(houseId).interiorLights))} the house lights`); } // =========================================================================== @@ -175,15 +176,17 @@ function setHouseDescriptionCommand(command, params, client) { let oldDescription = getHouseData(houseId).description; getHouseData(houseId).description = newHouseDescription; - for(let i in getHouseData(houseId).locations) { - if(getHouseData(houseId).locations[i].type == VRR_HOUSE_LOC_DOOR) { - setEntityData(getHouseData(houseId).entrancePickup, "vrr.label.name", getHouseData(houseId).description, true); - } - } + //for(let i in getHouseData(houseId).locations) { + // if(getHouseData(houseId).locations[i].type == VRR_HOUSE_LOC_DOOR) { + // setEntityData(getHouseData(houseId).entrancePickup, "vrr.label.name", getHouseData(houseId).description, true); + // } + //} + + setEntityData(getHouseData(houseId).entrancePickup, "vrr.label.name", getHouseData(houseId).description, true); getHouseData(houseId).needsSaved = true; - messageAdmins(`${getPlayerName(client)} renamed house ${getInlineChatColourByType("houseGreen")}${oldDescription} ${getInlineChatColourByName("white")}to ${getInlineChatColourByType("houseGreen")}${getHouseData(houseId).description}`); + messageAdmins(`${getInlineChatColourByName("lightGrey")}${getPlayerName(client)} ${getInlineChatColourByName("white")}renamed house ${getInlineChatColourByType("houseGreen")}${oldDescription} ${getInlineChatColourByName("white")}to ${getInlineChatColourByType("houseGreen")}${getHouseData(houseId).description}`); } // =========================================================================== @@ -287,10 +290,7 @@ function setHousePickupCommand(command, params, client) { getHouseData(houseId).entrancePickupModel = toInteger(typeParam); } - if(getHouseData(houseId).entrancePickup != null) { - deleteGameElement(getHouseData(houseId).entrancePickup); - } - + deleteHouseEntrancePickup(houseId); createHouseEntrancePickup(houseId); getHouseData(houseId).needsSaved = true; @@ -335,8 +335,9 @@ function setHouseInteriorTypeCommand(command, params, client) { messagePlayerInfo(client, `Interior Types: ${getInlineChatColourByName("lightGrey")}${Object.keys(getGameConfig().interiorTemplates[getServerGame()]).join(", ")}`) return false; } - getHouseData(houseId).exitPosition = getHouseData(houseId).exitPosition; - getHouseData(houseId).exitInterior = getHouseData(houseId).exitInterior; + + getHouseData(houseId).exitPosition = getGameConfig().interiorTemplates[getServerGame()][typeParam][0]; + getHouseData(houseId).exitInterior = getGameConfig().interiorTemplates[getServerGame()][typeParam][1]; getHouseData(houseId).exitDimension = getHouseData(houseId).databaseId+getGlobalConfig().houseDimensionStart; getHouseData(houseId).hasInterior = true; } @@ -417,14 +418,19 @@ function moveHouseEntranceCommand(command, params, client) { return false; } - getHouseData(houseId).locations[0].entrancePosition = getPlayerPosition(client); - getHouseData(houseId).locations[0].entranceDimension = getPlayerDimension(client); - getHouseData(houseId).locations[0].entranceInterior = getPlayerInterior(client); + getHouseData(houseId).entrancePosition = getPlayerPosition(client); + getHouseData(houseId).entranceDimension = getPlayerDimension(client); + getHouseData(houseId).entranceInterior = getPlayerInterior(client); - deleteAllHouseBlips(houseId); - deleteAllHousePickups(houseId); - createAllHouseBlips(houseId); - createAllHousePickups(houseId); + //deleteAllHouseBlips(houseId); + //deleteAllHousePickups(houseId); + //createAllHouseBlips(houseId); + //createAllHousePickups(houseId); + + deleteHouseEntrancePickup(houseId); + deleteHouseEntranceBlip(houseId); + createHouseEntrancePickup(houseId); + createHouseEntranceBlip(houseId); getHouseData(houseId).needsSaved = true; @@ -452,14 +458,19 @@ function moveHouseExitCommand(command, params, client) { getHouseData(houseId).locations = []; - getHouseData(houseId).locations[0].entrancePosition = getPlayerPosition(client); - getHouseData(houseId).locations[0].entranceDimension = getPlayerDimension(client); - getHouseData(houseId).locations[0].exitInterior = getPlayerInterior(client); + getHouseData(houseId).exitPosition = getPlayerPosition(client); + getHouseData(houseId).exitDimension = getPlayerDimension(client); + getHouseData(houseId).exitInterior = getPlayerInterior(client); - deleteAllHouseBlips(houseId); - deleteAllHousePickups(houseId); - createAllHouseBlips(houseId); - createAllHousePickups(houseId); + //deleteAllHouseBlips(houseId); + //deleteAllHousePickups(houseId); + //createAllHouseBlips(houseId); + //createAllHousePickups(houseId); + + deleteHouseExitPickup(houseId); + deleteHouseExitBlip(houseId); + createHouseExitPickup(houseId); + createHouseExitBlip(houseId); getHouseData(houseId).needsSaved = true; @@ -484,7 +495,6 @@ function deleteHouseCommand(command, params, client) { messagePlayerError("House not found!"); return false; } - tempHouseData = getHouseData(houseId); messageAdmins(`${getInlineChatColourByName("lightGrey")}${getPlayerName(client)} ${getInlineChatColourByName("white")}deleted house ${getInlineChatColourByType("houseGreen")}${getHouseData(houseId).description}`); deleteHouse(houseId, getPlayerData(client).accountData.databaseId); diff --git a/scripts/server/item.js b/scripts/server/item.js index 534e8ccf..06786939 100644 --- a/scripts/server/item.js +++ b/scripts/server/item.js @@ -819,11 +819,20 @@ function playerSwitchItem(client, newHotBarSlot) { logToConsole(LOG_DEBUG, `[VRR.Item] ${getPlayerDisplayForConsole(client)} switched from hotbar slot ${currentHotBarSlot} to ${newHotBarSlot}`); let currentHotBarItem = -1; + let newHotBarItem = -1; + + // Check if new slot is the same as the current one + // If true, clear active item slot (puts current item away) + if(currentHotBarSlot != -1 && newHotBarSlot != -1) { + if(currentHotBarSlot == newHotBarSlot) { + newHotBarSlot = -1; + } + } + if(currentHotBarSlot != -1) { currentHotBarItem = getPlayerData(client).hotBarItems[currentHotBarSlot]; } - let newHotBarItem = -1; if(newHotBarSlot != -1) { newHotBarItem = getPlayerData(client).hotBarItems[newHotBarSlot]; } @@ -1363,6 +1372,9 @@ function getItemValueDisplay(itemType, value) { } else if(getItemTypeData(itemType).useType == VRR_ITEM_USETYPE_PHONE) { return toString(value); } else if(getItemTypeData(itemType).useType == VRR_ITEM_USETYPE_WEAPON || getItemTypeData(itemType).useType == VRR_ITEM_USETYPE_TAZER) { + if(isMeleeWeapon(getItemTypeData(itemType).useId)) { + return false; + } return toString(value)+" rounds"; } else if(getItemTypeData(itemType).useType == VRR_ITEM_USETYPE_WALKIETALKIE) { return toString(toString(value).slice(0,-2)+"."+toString(value).slice(-1)+"MHz"); @@ -1371,7 +1383,7 @@ function getItemValueDisplay(itemType, value) { } else { return value; } - return "unknown"; + return false; } // =========================================================================== diff --git a/scripts/server/messaging.js b/scripts/server/messaging.js index f61e9633..6016f360 100644 --- a/scripts/server/messaging.js +++ b/scripts/server/messaging.js @@ -180,7 +180,7 @@ function messagePlayerMeAction(client, doingActionClient, messageText) { // =========================================================================== function messagePlayerClanChat(client, clanChattingClient, messageText) { - messagePlayerNormal(client, `👥 (${getClientSubAccountClanRank(clanChattingClient)}) ${getClientSubAccountName(clanChattingClient)} says (clan): ${messageText}`, getColourByType("clanChatMessage")); + messagePlayerNormal(client, `👥 ${getInlineChatColourByName("clanOrange")}${(getPlayerClanRankName(clanChattingClient) != false) ? getPlayerClanRankName(clanChattingClient) : "No Rank"} ${getCharacterFullName(clanChattingClient)} ${getInlineChatColourByName("white")}says (clan): ${getInlineChatColourByName("lightGrey")}${messageText}`, getColourByType("clanChatMessage")); } // =========================================================================== diff --git a/scripts/server/misc.js b/scripts/server/misc.js index 23659c4e..943768dc 100644 --- a/scripts/server/misc.js +++ b/scripts/server/misc.js @@ -242,7 +242,7 @@ function enterExitPropertyCommand(command, params, client) { if(doesBusinessHaveAnyItemsToBuy(closestBusinessId)) { messagePlayerInfo(client, "Use /buy to purchase items from this business"); } - updateInteriorLightsForPlayer(client, closestBusiness.lights); + updateInteriorLightsForPlayer(client, closestBusiness.interiorLights); setTimeout(function() { if(closestBusiness.streamingRadioStation != -1) { if(getPlayerData(client).streamingRadioStation != closestBusiness.streamingRadioStation) { @@ -281,17 +281,17 @@ function enterExitPropertyCommand(command, params, client) { } disableCityAmbienceForPlayer(client); setTimeout(function() { - setPlayerPosition(client, closestHouse.exitPosition); - setPlayerHeading(client, closestHouse.exitRotation); setPlayerDimension(client, closestHouse.exitDimension); setPlayerInterior(client, closestHouse.exitInterior); + setPlayerPosition(client, closestHouse.exitPosition); + setPlayerHeading(client, closestHouse.exitRotation); sendPlayerHouseGameScripts(client, closestHouse.index); setTimeout(function() { if(isFadeCameraSupported()) { fadeCamera(client, true, 1.0); } getPlayerData(client).pedState = VRR_PEDSTATE_READY; - updateInteriorLightsForPlayer(client, closestHouse.lights); + updateInteriorLightsForPlayer(client, closestHouse.interiorLights); setTimeout(function() { if(closestHouse.streamingRadioStation != -1) { if(getPlayerData(client).streamingRadioStation != closestHouse.streamingRadioStation) { diff --git a/scripts/server/moderation.js b/scripts/server/moderation.js index ee5f21e1..2a224fa1 100644 --- a/scripts/server/moderation.js +++ b/scripts/server/moderation.js @@ -196,6 +196,7 @@ function gotoPlayerCommand(command, params, client) { setPlayerHeading(client, getPlayerHeading(targetClient)); setPlayerInterior(client, getPlayerInterior(targetClient)); setPlayerDimension(client, getPlayerInterior(targetClient)); + updateInteriorLightsForPlayer(client, true); }, 1000); messagePlayerSuccess(client, `You teleported to ${getInlineChatColourByName("lightGrey")}${getPlayerName(targetClient)}`); @@ -203,6 +204,27 @@ function gotoPlayerCommand(command, params, client) { // =========================================================================== +function getGeoIPInformationCommand(command, params, client) { + if(areParamsEmpty(params)) { + messagePlayerSyntax(client, getCommandSyntaxText(command)); + return false; + } + + let targetClient = getPlayerFromParams(params); + if(!targetClient) { + messagePlayerError(client, "That player is not connected!"); + return false; + } + + let countryName = module.geoip.getCountryName(getGlobalConfig().geoIPCountryDatabaseFilePath, targetClient.ip); + let subDivisionName = module.geoip.getSubdivisionName(getGlobalConfig().geoIPCityDatabaseFilePath, targetClient.ip); + let cityName = module.geoip.getCityName(getGlobalConfig().geoIPCityDatabaseFilePath, targetClient.ip); + + messagePlayerInfo(client, `${getInlineChatColourByName("lightGrey")}${targetClient.name} ${getInlineChatColourByName("white")}is from ${getInlineChatColourByName("lightGrey")}${cityName}, ${subDivisionName}, ${countryName}`); +} + +// =========================================================================== + function gotoVehicleCommand(command, params, client) { if(areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); @@ -220,6 +242,7 @@ function gotoVehicleCommand(command, params, client) { setPlayerPosition(client, getPosAbovePos(getVehiclePosition(vehicle), 3.0)); setPlayerInterior(client, 0); setPlayerDimension(client, getElementDimension(vehicle)); + updateInteriorLightsForPlayer(client, true); }, 500); messagePlayerSuccess(client, `You teleported to a ${getInlineChatColourByType("vehiclePurple")}${getVehicleName(vehicle)} ${getInlineChatColourByName("lightGrey")}(ID ${vehicle.id})`); @@ -245,6 +268,7 @@ function gotoBusinessCommand(command, params, client) { setPlayerPosition(client, getBusinessData(businessId).entrancePosition); setPlayerInterior(client, getBusinessData(businessId).entranceInterior); setPlayerDimension(client, getBusinessData(businessId).entranceDimension); + updateInteriorLightsForPlayer(client, true); }, 500); messagePlayerSuccess(client, `You teleported to business ${getInlineChatColourByType("businessBlue")}${getBusinessData(businessId).name} ${getInlineChatColourByName("lightGrey")}(ID ${businessId})`); @@ -270,6 +294,7 @@ function gotoGameLocationCommand(command, params, client) { setPlayerPosition(client, getGameData().locations[getServerGame()][gameLocationId][1]); setPlayerInterior(client, 0); setPlayerDimension(client, 0); + updateInteriorLightsForPlayer(client, true); }, 500); messagePlayerSuccess(client, `You teleported to game location ${getInlineChatColourByName("lightGrey")}${getGameData().locations[getServerGame()][gameLocationId][0]}`); @@ -295,6 +320,7 @@ function gotoHouseCommand(command, params, client) { setPlayerPosition(client, getHouseData(houseId).entrancePosition); setPlayerInterior(client, getHouseData(houseId).entranceInterior); setPlayerDimension(client, getHouseData(houseId).entranceDimension); + updateInteriorLightsForPlayer(client, true); }, 500); messagePlayerSuccess(client, `You teleported to business ${getInlineChatColourByType("businessBlue")}${getHouseData(houseId).description} ${getInlineChatColourByName("lightGrey")}(ID ${houseId})`); @@ -328,12 +354,25 @@ function gotoJobLocationCommand(command, params, client) { setPlayerPosition(client, getJobData(jobId).locations[jobLocationId].position); setPlayerInterior(client, getJobData(jobId).locations[jobLocationId].interior); setPlayerDimension(client, getJobData(jobId).locations[jobLocationId].dimension); + updateInteriorLightsForPlayer(client, true); messagePlayerSuccess(client, `You teleported to location ${getInlineChatColourByName("lightGrey")}${jobLocationId} ${getInlineChatColourByName("white")}for the ${getInlineChatColourByName("lightGrey")}${getJobData(jobId).name} ${getInlineChatColourByName("white")}job`); } // =========================================================================== +function gotoNewPlayerSpawnCommand(command, params, client) { + client.player.velocity = toVector3(0.0, 0.0, 0.0); + setPlayerPosition(client, getServerConfig().newCharacter.spawnPosition); + setPlayerInterior(client, getServerConfig().newCharacter.spawnInterior); + setPlayerDimension(client, getServerConfig().newCharacter.spawnDimension); + updateInteriorLightsForPlayer(client, true); + + messagePlayerSuccess(client, `You teleported to the new character spawn location!`); +} + +// =========================================================================== + function gotoPositionCommand(command, params, client) { if(areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); @@ -347,14 +386,15 @@ function gotoPositionCommand(command, params, client) { let int = splitParams[3] || getPlayerInterior(client); let vw = splitParams[4] || getPlayerDimension(client); - let newPosition = toVector3(Number(x), Number(y), Number(z)); + let newPosition = toVector3(toInteger(x), toInteger(y), toInteger(z)); let jobId = getJobFromParams(splitParams[0]) || getClosestJobLocation(getPlayerPosition(client)).job; client.player.velocity = toVector3(0.0, 0.0, 0.0); setPlayerPosition(client, newPosition); - setPlayerInterior(client, Number(int)); - setPlayerDimension(client, Number(vw)); + setPlayerInterior(client, toInteger(int)); + setPlayerDimension(client, toInteger(vw)); + updateInteriorLightsForPlayer(client, true); messagePlayerSuccess(client, `You teleported to coordinates ${getInlineChatColourByName("lightGrey")}${x}, ${y}, ${z} with interior ${int} and dimension ${vw}`); } diff --git a/scripts/server/native/gtac.js b/scripts/server/native/gtac.js index 74b21b35..da8e36fc 100644 --- a/scripts/server/native/gtac.js +++ b/scripts/server/native/gtac.js @@ -3201,6 +3201,7 @@ let gameData = { { // GTA San Andreas policeStation: 1247, + fireStation: 1318, hospital: 1240, ammunation: 1239, @@ -3239,12 +3240,12 @@ let gameData = { }, { // GTA San Andreas - business: 255, - house: 255, - bank: 255, - clothes: 255, - info: 255, - job: 255, + business: 1, + house: 1, + bank: 1, + clothes: 1, + info: 1, + job: 1, } ], @@ -4207,7 +4208,7 @@ function getAllowedSkinDataBySkinId(skinId) { // =========================================================================== function getPlayerPosition(client) { - if(getServerGame() == GAME_GTA_IV) { + if(doesGameHaveServerSideElements()) { return getPlayerData(client).syncPosition; } else { if(client.player != null) { diff --git a/scripts/server/subaccount.js b/scripts/server/subaccount.js index 8a627b4f..3207d40c 100644 --- a/scripts/server/subaccount.js +++ b/scripts/server/subaccount.js @@ -63,9 +63,26 @@ function loadSubAccountsFromAccount(accountId) { if(dbQuery) { while(dbAssoc = fetchQueryAssoc(dbQuery)) { let tempSubAccount = new serverClasses.subAccountData(dbAssoc); + + // Make sure skin is valid if(tempSubAccount.skin == -1) { tempSubAccount.skin = getServerConfig().newCharacter.skin; } + + // Check if clan and rank are still valid + if(tempSubAccount.clan != 0) { + if(!getClanData(getClanIdFromDatabaseId(tempSubAccount.clan))) { + tempSubAccount.clan = 0; + tempSubAccount.clanRank = 0; + tempSubAccount.clanTitle = ""; + tempSubAccount.clanFlags = 0; + } else { + if(!getClanRankData(getClanIdFromDatabaseId(tempSubAccount.clan), tempSubAccount.clanRank)) { + tempSubAccount.clanRank = 0; + } + } + } + tempSubAccounts.push(tempSubAccount); } freeDatabaseQuery(dbQuery); @@ -217,7 +234,7 @@ function showCharacterSelectToClient(client) { getPlayerData(client).currentSubAccount = 0; logToConsole(LOG_DEBUG, `[VRR.SubAccount] Setting ${getPlayerDisplayForConsole(client)}'s character to ID ${getPlayerData(client).currentSubAccount}`); let tempSubAccount = getPlayerData(client).subAccounts[0]; - let clanName = (tempSubAccount.clan != 0) ? getClanData(tempSubAccount.clan).name : "None"; + let clanName = (tempSubAccount.clan != 0) ? getClanData(getClanIdFromDatabaseId(tempSubAccount.clan)).name : "None"; let lastPlayedText = (tempSubAccount.lastLogin != 0) ? `${msToTime(getCurrentUnixTimestamp()-tempSubAccount.lastLogin)} ago` : "Never"; showPlayerCharacterSelectGUI(client, tempSubAccount.firstName, tempSubAccount.lastName, tempSubAccount.cash, clanName, lastPlayedText, tempSubAccount.skin); @@ -354,11 +371,16 @@ function selectCharacter(client, characterId = -1) { logToConsole(LOG_DEBUG, `[VRR.SubAccount] Spawning ${getPlayerDisplayForConsole(client)} as character ID ${getPlayerData(client).currentSubAccount} with skin ${skin} (${spawnPosition.x}, ${spawnPosition.y}, ${spawnPosition.z})`); //setPlayerCameraLookAt(client, getPosBehindPos(spawnPosition, spawnHeading, 5), spawnPosition); getPlayerData(client).pedState = VRR_PEDSTATE_SPAWNING; - if(getServerGame() == GAME_GTA_IV) { - spawnPlayer(client, spawnPosition, spawnHeading, skin); - } else { + + if(!isGTAIV()) { spawnPlayer(client, spawnPosition, spawnHeading, skin, spawnInterior, spawnDimension); + } else { + setPlayerPosition(client, spawnPosition); + setPlayerHeading(client, spawnHeading); + setPlayerSkin(client, skin); + restorePlayerCamera(client); } + logToConsole(LOG_DEBUG, `[VRR.SubAccount] Spawned ${getPlayerDisplayForConsole(client)} as character ID ${getPlayerData(client).currentSubAccount} with skin ${skin} (${spawnPosition.x}, ${spawnPosition.y}, ${spawnPosition.z})`); setTimeout(function() { diff --git a/scripts/server/timers.js b/scripts/server/timers.js index c3798634..63fcd926 100644 --- a/scripts/server/timers.js +++ b/scripts/server/timers.js @@ -89,15 +89,21 @@ function updatePings() { // =========================================================================== function checkServerGameTime() { - if(getServerConfig().minute >= 59) { - getServerConfig().minute = 0; - if(getServerConfig().hour >= 23) { - getServerConfig().hour = 0; + if(!getServerConfig().useRealTime) { + if(getServerConfig().minute >= 59) { + getServerConfig().minute = 0; + if(getServerConfig().hour >= 23) { + getServerConfig().hour = 0; + } else { + getServerConfig().hour = getServerConfig().hour + 1; + } } else { - getServerConfig().hour = getServerConfig().hour + 1; + getServerConfig().minute = getServerConfig().minute + 1; } } else { - getServerConfig().minute = getServerConfig().minute + 1; + let dateTime = getCurrentTimeStampWithTimeZone(getServerConfig().realTimeZone); + getServerConfig().hour = dateTime.getHours(); + getServerConfig().minute = dateTime.getMinutes(); } updateTimeRule(); diff --git a/scripts/server/utilities.js b/scripts/server/utilities.js index f5d0b6d6..ca985905 100644 --- a/scripts/server/utilities.js +++ b/scripts/server/utilities.js @@ -752,13 +752,15 @@ function getClanFromParams(params) { function getClanRankFromParams(clanId, params) { if(isNaN(params)) { for(let i in getClanData(clanId).ranks) { - if(toLowerCase(getClanData(clanId).ranks[i].name).indexOf(toLowerCase(params)) != -1) { + if((toLowerCase(getClanData(clanId).ranks[i].name).indexOf(toLowerCase(params)) != -1)) { return i; } } } else { - if(typeof getClanData(clanId).ranks[params] != "undefined") { - return toInteger(params); + for(let i in getClanData(clanId).ranks) { + if(getClanData(clanId).ranks[i].level == toInteger(params)) { + return i; + } } } @@ -1535,4 +1537,23 @@ function getAllHousesOwnedByPlayer(client) { return getServerData().houses.filter((h) => h.ownerType == VRR_HOUSEOWNER_PLAYER && h.ownerId == getPlayerCurrentSubAccount(client).databaseId); } +// =========================================================================== + +function addPositiveNegativeSymbol(value) { + return (value >= 0) ? `+${value}` : `${value}`; +} + +// =========================================================================== + +function getCurrentTimeStampWithTimeZone(timeZone) { + let date = new Date(); + + let utcDate = new Date(date.toLocaleString('en-US', { timeZone: "UTC" })); + let tzDate = new Date(date.toLocaleString('en-US', { timeZone: timeZone })); + let offset = utcDate.getTime() - tzDate.getTime(); + + date.setTime( date.getTime() + offset ); + + return date; +}; // =========================================================================== \ No newline at end of file diff --git a/scripts/server/vehicle.js b/scripts/server/vehicle.js index c781d1f6..c413b1a0 100644 --- a/scripts/server/vehicle.js +++ b/scripts/server/vehicle.js @@ -143,7 +143,6 @@ function saveVehicleToDatabase(vehicleDataId) { ["veh_extra11", tempVehicleData.extras[10]], ["veh_extra12", tempVehicleData.extras[11]], ["veh_extra13", tempVehicleData.extras[12]], - ["veh_locked", intToBool(tempVehicleData.locked)], ["veh_engine", intToBool(tempVehicleData.engine)], ["veh_lights", intToBool(tempVehicleData.lights)], ["veh_health", toInteger(tempVehicleData.health)], @@ -353,11 +352,9 @@ function deleteVehicleCommand(command, params, client) { quickDatabaseQuery(`DELETE FROM veh_main WHERE veh_id = ${getVehicleData(vehicle).databaseId}`); - getServerData().vehicles[dataIndex] = null; + getServerData().vehicles.splice(dataIndex, 1); destroyElement(vehicle); - getVehicleData(vehicle).needsSaved = true; - messagePlayerSuccess(client, `The ${vehicleName} has been deleted!`); } @@ -507,7 +504,7 @@ function vehicleRepairCommand(command, params, client) { getVehicleData(vehicle).needsSaved = true; - meActionToNearbyPlayers(client, `repairs the ${getVehicleName(vehicle)}!`); + meActionToNearbyPlayers(client, `repairs the ${getVehicleName(vehicle)}`); } // =========================================================================== @@ -720,7 +717,7 @@ function setVehicleJobCommand(command, params, client) { //} getVehicleData(vehicle).ownerType = VRR_VEHOWNER_JOB; - getVehicleData(vehicle).ownerId = jobId; + getVehicleData(vehicle).ownerId = getJobData(jobId).databaseId; getVehicleData(vehicle).needsSaved = true; diff --git a/scripts/shared/const.js b/scripts/shared/const.js index 55d9d691..c6c295f0 100644 --- a/scripts/shared/const.js +++ b/scripts/shared/const.js @@ -11,7 +11,7 @@ const VRR_LABEL_JOB = 1; const VRR_LABEL_BUSINESS = 2; const VRR_LABEL_HOUSE = 3; -const VRR_LABEL_EXIT = 3; +const VRR_LABEL_EXIT = 4; // Log Levels const LOG_ALL = -1;