// =========================================================================== // Asshat Gaming Roleplay // https://github.com/VortrexFTW/agrp_main // (c) 2022 Asshat Gaming // =========================================================================== // FILE: job.js // DESC: Provides job functions and usage // TYPE: Server (JavaScript) // =========================================================================== // Job Types const AGRP_JOB_NONE = 0; const AGRP_JOB_POLICE = 1; const AGRP_JOB_MEDICAL = 2; const AGRP_JOB_FIRE = 3; const AGRP_JOB_BUS = 4; const AGRP_JOB_TAXI = 5; const AGRP_JOB_GARBAGE = 6; const AGRP_JOB_WEAPON = 7; const AGRP_JOB_DRUG = 8; const AGRP_JOB_PIZZA = 9; const AGRP_JOB_GENERIC = 10; // =========================================================================== // Job Route States const AGRP_JOB_ROUTE_STATE_NONE = 0; // None const AGRP_JOB_ROUTE_STATE_INPROGRESS = 1; // Route is in progress. Player is in between stops but not at the last one. const AGRP_JOB_ROUTE_STATE_LASTSTOP = 2; // Player is heading to the last stop on the route const AGRP_JOB_ROUTE_STATE_PAUSED = 3; // Route is paused for some reason. For police, this could be player accepted callout and once finished, patrol route will resume const AGRP_JOB_ROUTE_STATE_ATSTOP = 4; // For bus/trash stops that freeze player, this is the state when they're at one // =========================================================================== // Job Route Location Types const AGRP_JOB_ROUTE_LOCATION_TYPE_NONE = 0; // None const AGRP_JOB_ROUTE_LOCATION_TYPE_CHECKPOINT = 1; // Checkpoint (used for bus routes) const AGRP_JOB_ROUTE_LOCATION_TYPE_BURNING_VEHICLE = 2; // Burning vehicle (used for firefighter job) const AGRP_JOB_ROUTE_LOCATION_TYPE_INJURED_PED = 3; // Injured ped (used for paramedic job) const AGRP_JOB_ROUTE_LOCATION_TYPE_GROUND_GARBAGE = 4; // Mess/Garbage on ground (used for street sweeper job) const AGRP_JOB_ROUTE_LOCATION_TYPE_GARBAGE_BIN = 5; // Garbage in bin (used for trash collector pickup) // =========================================================================== /** * @class Representing a job's data. Loaded and saved in the database * @property {Array.} equipment * @property {Array.} uniforms * @property {Array.} locations * @property {Array.} routes * @property {Array.} whiteList * @property {Array.} blackList * @property {Array.} ranks */ class JobData { constructor(dbAssoc = false) { this.databaseId = 0; this.serverId = 0; this.type = AGRP_JOB_NONE; this.name = "Unnamed"; this.enabled = true; this.blipModel = -1 this.pickupModel = -1 this.colour = toColour(0, 0, 0, 255); this.whiteListEnabled = false; this.blackListEnabled = false; this.walkieTalkieFrequency = 0; this.index = -1; this.needsSaved = false; this.whoCreated = 0; this.whenCreated = 0; this.equipment = []; this.uniforms = []; this.locations = []; this.whiteList = []; this.blackList = []; this.routes = []; this.ranks = []; if (dbAssoc) { this.databaseId = dbAssoc["job_id"]; this.serverId = dbAssoc["job_server"]; this.type = dbAssoc["job_type"]; this.name = dbAssoc["job_name"]; this.enabled = dbAssoc["job_enabled"]; this.blipModel = dbAssoc["job_blip"]; this.pickupModel = dbAssoc["job_pickup"]; this.colour = toColour(dbAssoc["job_colour_r"], dbAssoc["job_colour_g"], dbAssoc["job_colour_b"], 255); this.whiteListEnabled = dbAssoc["job_wl"]; this.blackListEnabled = dbAssoc["job_bl"]; this.walkieTalkieFrequency = dbAssoc["job_walkietalkiefreq"]; this.whoCreated = dbAssoc["job_who_added"]; this.whenCreated = dbAssoc["job_when_added"]; this.equipment = []; this.uniforms = []; this.locations = []; this.whiteList = []; this.blackList = []; this.routes = []; this.ranks = []; } } }; // =========================================================================== /** * @class Representing a job route's data. Loaded and saved in the database * @property {Array.} locations */ class JobRouteData { constructor(dbAssoc = false) { this.databaseId = 0; this.name = ""; this.jobId = 0; this.locationId = 0; this.enabled = false; this.index = -1; this.jobIndex = -1; this.locationIndex = -1; this.needsSaved = false; this.pay = 0; this.vehicleColour1 = 1; this.vehicleColour2 = 1; this.detail = 0; this.startMessage = ""; this.finishMessage = ""; //this.failedMessage = ""; this.locationArriveMessage = ""; this.locationGotoMessage = ""; this.locations = []; this.whoCreated = 0; this.whenCreated = 0; this.sphere = null; if (dbAssoc) { this.databaseId = toInteger(dbAssoc["job_route_id"]); this.name = toString(dbAssoc["job_route_name"]); this.jobId = toInteger(dbAssoc["job_route_job"]); this.locationId = toInteger(dbAssoc["job_route_job_loc"]); this.enabled = intToBool(toInteger(dbAssoc["job_route_enabled"])); this.pay = toInteger(dbAssoc["job_route_pay"]); this.startMessage = toString(dbAssoc["job_route_start_msg"]); this.finishMessage = toString(dbAssoc["job_route_finish_msg"]); //this.finishMessage = toString(dbAssoc["job_route_failed_msg"]); this.locationArriveMessage = toString(dbAssoc["job_route_loc_arrive_msg"]); this.locationGotoMessage = toString(dbAssoc["job_route_loc_goto_msg"]); this.vehicleColour1 = toInteger(dbAssoc["job_route_veh_colour1"]); this.vehicleColour2 = toInteger(dbAssoc["job_route_veh_colour2"]); this.detail = toInteger(dbAssoc["job_route_detail"]); this.whoCreated = dbAssoc["job_route_who_added"]; this.whenCreated = dbAssoc["job_route_when_added"]; this.sphere = null; } } }; // =========================================================================== /** * @class Representing a job route locations's data. Loaded and saved in the database */ class JobRouteLocationData { constructor(dbAssoc = false) { this.databaseId = 0; this.name = ""; this.routeId = 0; this.enabled = false; this.index = -1; this.jobIndex = -1; this.routeIndex = -1; this.needsSaved = false; this.position = toVector3(0.0, 0.0, 0.0); this.stopDelay = 0; this.pay = 0; this.type = AGRP_JOB_ROUTE_LOCATION_TYPE_NONE; this.gotoMessage = ""; this.departMessage = ""; this.whoCreated = 0; this.whenCreated = 0; if (dbAssoc) { this.databaseId = toInteger(dbAssoc["job_route_loc_id"]); this.name = toString(dbAssoc["job_route_loc_name"]); this.routeId = toInteger(dbAssoc["job_route_loc_route"]); this.enabled = intToBool(toInteger(dbAssoc["job_route_loc_enabled"])); this.position = toVector3(toFloat(dbAssoc["job_route_loc_x"]), toFloat(dbAssoc["job_route_loc_y"]), toFloat(dbAssoc["job_route_loc_z"])); this.stopDelay = toInteger(dbAssoc["job_route_loc_delay"]); this.pay = toInteger(dbAssoc["job_route_loc_pay"]); this.arriveMessage = toInteger(dbAssoc["job_route_loc_arrive_msg"]); this.gotoMessage = toInteger(dbAssoc["job_route_loc_goto_msg"]); this.whoCreated = dbAssoc["job_route_loc_who_added"]; this.whenCreated = dbAssoc["job_route_loc_when_added"]; } } }; // =========================================================================== /** * @class Representing a job equipment set/loadout's data. Loaded and saved in the database * @property {Array.} items */ class JobEquipmentData { constructor(dbAssoc = false) { this.databaseId = 0; this.job = 0; this.name = "Unnamed"; this.requiredRank = 0; this.enabled = false; this.index = -1; this.jobIndex = -1; this.needsSaved = false; this.items = []; this.whoCreated = 0; this.whenCreated = 0; if (dbAssoc) { this.databaseId = dbAssoc["job_equip_id"]; this.job = dbAssoc["job_equip_job"]; this.name = dbAssoc["job_equip_name"]; this.requiredRank = dbAssoc["job_equip_minrank"]; this.enabled = dbAssoc["job_equip_enabled"]; this.whoCreated = dbAssoc["job_equip_who_added"]; this.whenCreated = dbAssoc["job_equip_when_added"]; } } }; // =========================================================================== /** * @class Representing a job equipment set item's data. Loaded and saved in the database */ class JobEquipmentItemData { constructor(dbAssoc = false) { this.databaseId = 0; this.equipmentId = 0; this.itemType = 0; this.value = 0; this.enabled = false; this.index = -1; this.jobIndex = -1; this.needsSaved = false; this.whoCreated = 0; this.whenCreated = 0; if (dbAssoc) { this.databaseId = dbAssoc["job_equip_item_id"]; this.equipmentId = dbAssoc["job_equip_item_equip"]; this.itemType = dbAssoc["job_equip_item_type"]; this.value = dbAssoc["job_equip_item_value"]; this.enabled = dbAssoc["job_equip_item_enabled"]; this.whoCreated = dbAssoc["job_equip_item_who_added"]; this.whenCreated = dbAssoc["job_equip_item_when_added"]; } } }; // =========================================================================== /** * @class Representing a job uniform's data. Loaded and saved in the database */ class JobUniformData { constructor(dbAssoc = false) { this.databaseId = 0; this.job = 0; this.name = "Unnamed"; this.requiredRank = 0 this.skin = -1; this.enabled = false; this.index = -1; this.jobIndex = -1; this.needsSaved = false; this.whoCreated = 0; this.whenCreated = 0; /* this.bodyParts = { hair: [0, 0], head: [0, 0], upper: [0, 0], lower: [0, 0], }; this.bodyProps = { hair: [0, 0], eyes: [0, 0], head: [0, 0], leftHand: [0, 0], rightHand: [0, 0], leftWrist: [0, 0], rightWrist: [0, 0], hip: [0, 0], leftFoot: [0, 0], rightFoot: [0, 0], }; */ if (dbAssoc) { this.databaseId = dbAssoc["job_uniform_id"]; this.job = dbAssoc["job_uniform_job"]; this.name = dbAssoc["job_uniform_name"]; this.requiredRank = dbAssoc["job_uniform_minrank"]; this.skin = dbAssoc["job_uniform_skin"]; this.enabled = intToBool(dbAssoc["job_uniform_enabled"]); this.whoCreated = dbAssoc["job_uniform_who_added"]; this.whenCreated = dbAssoc["job_uniform_when_added"]; /* this.bodyParts = { hair: [toInteger(dbAssoc["job_uniform_hd_part_hair_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_part_hair_texture"]) || 0], head: [toInteger(dbAssoc["job_uniform_hd_part_head_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_part_head_texture"]) || 0], upper: [toInteger(dbAssoc["job_uniform_hd_part_upper_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_part_upper_texture"]) || 0], lower: [toInteger(dbAssoc["job_uniform_hd_part_lower_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_part_lower_texture"]) || 0], }; this.bodyProps = { hair: [toInteger(dbAssoc["job_uniform_hd_prop_hair_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_prop_hair_texture"]) || 0], eyes: [toInteger(dbAssoc["job_uniform_hd_prop_eyes_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_prop_eyes_texture"]) || 0], head: [toInteger(dbAssoc["job_uniform_hd_prop_head_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_prop_head_texture"]) || 0], leftHand: [toInteger(dbAssoc["job_uniform_hd_prop_lefthand_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_prop_lefthand_texture"]) || 0], rightHand: [toInteger(dbAssoc["job_uniform_hd_prop_righthand_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_prop_righthand_texture"]) || 0], leftWrist: [toInteger(dbAssoc["job_uniform_hd_prop_leftwrist_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_prop_leftwrist_texture"]) || 0], rightWrist: [toInteger(dbAssoc["job_uniform_hd_prop_rightwrist_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_prop_rightwrist_texture"]) || 0], hip: [toInteger(dbAssoc["job_uniform_hd_prop_hip_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_prop_hip_texture"]) || 0], leftFoot: [toInteger(dbAssoc["job_uniform_hd_prop_leftfoot_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_prop_leftfoot_texture"]) || 0], rightFoot: [toInteger(dbAssoc["job_uniform_hd_prop_rightfoot_model"]) || 0, toInteger(dbAssoc["job_uniform_hd_prop_rightfoot_texture"]) || 0], }; */ } } }; // =========================================================================== /** * @class JobLocationData Representing a job uniform's data. Loaded and saved in the database */ class JobLocationData { constructor(dbAssoc = false) { this.databaseId = 0; this.jobId = 0; this.position = toVector3(0.0, 0.0, 0.0); this.blip = false; this.pickup = false; this.enabled = false; this.interior = 0; this.dimension = 0; this.index = -1; this.jobIndex = -1; this.needsSaved = false; this.routeCache = []; this.whoCreated = 0; this.whenCreated = 0; if (dbAssoc) { this.databaseId = dbAssoc["job_loc_id"]; this.jobId = dbAssoc["job_loc_job"]; this.position = toVector3(dbAssoc["job_loc_pos_x"], dbAssoc["job_loc_pos_y"], dbAssoc["job_loc_pos_z"]); this.blip = false; this.pickup = false; this.enabled = intToBool(dbAssoc["job_loc_enabled"]); this.interior = dbAssoc["job_loc_int"]; this.dimension = dbAssoc["job_loc_vw"]; this.whoCreated = dbAssoc["job_loc_who_added"]; this.whenCreated = dbAssoc["job_loc_when_added"]; } } }; // =========================================================================== /** * @class JobRankData Representing a job rank's data. Loaded and saved in the database */ class JobRankData { constructor(dbAssoc = false) { this.databaseId = 0; this.jobId = 0; this.index = -1; this.jobIndex = -1; this.name = ""; this.level = 0; this.enabled = false; this.pay = 0; this.whoCreated = 0; this.whenCreated = 0; this.flags = 0; this.needsSaved = false; if (dbAssoc) { this.databaseId = toInteger(dbAssoc["job_rank_id"]); this.jobId = toInteger(dbAssoc["job_rank_job"]); this.name = toString(dbAssoc["job_rank_name"]); this.level = toInteger(dbAssoc["job_rank_level"]); this.enabled = intToBool(dbAssoc["job_rank_enabled"]); this.pay = toInteger(dbAssoc["job_rank_pay"]); this.whoCreated = toInteger(dbAssoc["job_rank_who_added"]); this.whenCreated = toInteger(dbAssoc["job_rank_when_added"]); this.flags = toInteger(dbAssoc["job_rank_flags"]); } } }; // =========================================================================== class JobWhiteListData { constructor(dbAssoc = false) { this.databaseId = 0; this.job = 0; this.subAccount = 0 this.enabled = false; this.index = -1; this.jobIndex = -1; this.needsSaved = false; this.whoCreated = 0; this.whenCreated = 0; if (dbAssoc) { this.databaseId = dbAssoc["job_wl_id"]; this.job = dbAssoc["job_wl_job"]; this.subAccount = dbAssoc["job_wl_sacct"] this.enabled = dbAssoc["job_wl_enabled"]; this.whoCreated = dbAssoc["job_wl_who_added"]; this.whenCreated = dbAssoc["job_wl_when_added"]; } } }; // =========================================================================== class JobBlackListData { constructor(dbAssoc = false) { this.databaseId = 0; this.job = 0; this.subAccount = 0 this.enabled = false; this.index = -1; this.jobIndex = -1; this.needsSaved = false; this.whoCreated = 0; this.whenCreated = 0; if (dbAssoc) { this.databaseId = dbAssoc["job_bl_id"]; this.job = dbAssoc["job_bl_job"]; this.subAccount = dbAssoc["job_bl_sacct"] this.enabled = dbAssoc["job_bl_enabled"]; this.whoCreated = dbAssoc["job_bl_who_added"]; this.whenCreated = dbAssoc["job_bl_when_added"]; } } }; // =========================================================================== // For use with the /jobrouteloctype command let jobRouteLocationTypeNames = { Checkpoint: AGRP_JOB_ROUTE_LOCATION_TYPE_CHECKPOINT, StreetClean: AGRP_JOB_ROUTE_LOCATION_TYPE_GROUND_GARBAGE, GroundGarbage: AGRP_JOB_ROUTE_LOCATION_TYPE_GROUND_GARBAGE, GarbageBin: AGRP_JOB_ROUTE_LOCATION_TYPE_GARBAGE_BIN, GarbagePickup: AGRP_JOB_ROUTE_LOCATION_TYPE_GARBAGE_BIN, BurningVehicle: AGRP_JOB_ROUTE_LOCATION_TYPE_BURNING_VEHICLE, InjuredPed: AGRP_JOB_ROUTE_LOCATION_TYPE_INJURED_PED, } // =========================================================================== function initJobScript() { logToConsole(LOG_DEBUG, "[VRR.Job]: Initializing job script ..."); logToConsole(LOG_INFO, "[VRR.Job]: Job script initialized successfully!"); return true; } // =========================================================================== function loadJobsFromDatabase() { logToConsole(LOG_DEBUG, "[VRR.Job]: Loading jobs from database ..."); let tempJobs = []; let dbConnection = connectToDatabase(); let dbQuery = null; let dbAssoc; if (dbConnection) { dbQuery = queryDatabase(dbConnection, `SELECT * FROM job_main WHERE job_deleted = 0 AND job_enabled = 1 AND job_server = ${getServerId()}`); if (dbQuery) { if (dbQuery.numRows > 0) { while (dbAssoc = fetchQueryAssoc(dbQuery)) { let tempJobData = new JobData(dbAssoc); tempJobData.locations = loadJobLocationsFromDatabase(tempJobData.databaseId); tempJobData.equipment = loadJobEquipmentsFromDatabase(tempJobData.databaseId); tempJobData.uniforms = loadJobUniformsFromDatabase(tempJobData.databaseId); tempJobData.routes = loadJobRoutesFromDatabase(tempJobData.databaseId); tempJobData.ranks = loadJobRanksFromDatabase(tempJobData.databaseId); tempJobs.push(tempJobData); logToConsole(LOG_VERBOSE, `[VRR.Job]: Job '${tempJobData.name}' loaded from database successfully!`); } } freeDatabaseQuery(dbQuery); } disconnectFromDatabase(dbConnection); } logToConsole(LOG_DEBUG, `[VRR.Job]: ${tempJobs.length} jobs loaded from database successfully!`); return tempJobs; } // =========================================================================== function loadAllJobEquipmentFromDatabase() { for (let i in getServerData().jobs) { getServerData().jobs[i].equipment = loadJobEquipmentsFromDatabase(getServerData().jobs[i].databaseId); } } // =========================================================================== function loadAllJobUniformsFromDatabase() { for (let i in getServerData().jobs) { getServerData().jobs[i].uniforms = loadJobUniformsFromDatabase(getServerData().jobs[i].databaseId); } } // =========================================================================== function loadAllJobRoutesFromDatabase() { for (let i in getServerData().jobs) { getServerData().jobs[i].routes = loadJobRoutesFromDatabase(getServerData().jobs[i].databaseId); } } // =========================================================================== function loadAllJobLocationsFromDatabase() { for (let i in getServerData().jobs) { getServerData().jobs[i].locations = loadJobLocationsFromDatabase(getServerData().jobs[i].databaseId); } } // =========================================================================== function loadJobRanksFromDatabase(jobDatabaseId) { logToConsole(LOG_DEBUG, `[VRR.Job]: Loading ranks for job ${jobDatabaseId} from database ...`); let tempJobRanks = []; let dbConnection = connectToDatabase(); let dbQuery = null; let dbAssoc; if (dbConnection) { dbQuery = queryDatabase(dbConnection, `SELECT * FROM job_rank WHERE job_rank_deleted = 0 AND job_rank_enabled = 1 AND job_rank_job = ${jobDatabaseId}`); if (dbQuery) { if (dbQuery.numRows > 0) { while (dbAssoc = fetchQueryAssoc(dbQuery)) { let tempJobRankData = new JobRankData(dbAssoc); tempJobRanks.push(tempJobRankData); logToConsole(LOG_VERBOSE, `[VRR.Job]: Job rank '${tempJobRankData.name}' loaded from database successfully!`); } } freeDatabaseQuery(dbQuery); } disconnectFromDatabase(dbConnection); } logToConsole(LOG_DEBUG, `[VRR.Job]: ${tempJobRanks.length} ranks for job ${jobDatabaseId} loaded from database successfully!`); return tempJobRanks; } // =========================================================================== function loadJobRoutesFromDatabase(jobDatabaseId) { logToConsole(LOG_DEBUG, `[VRR.Job]: Loading job routes for job ${jobDatabaseId} from database ...`); let tempJobRoutes = []; let dbConnection = connectToDatabase(); let dbQuery = null; let dbAssoc; if (dbConnection) { dbQuery = queryDatabase(dbConnection, `SELECT * FROM job_route WHERE job_route_deleted = 0 AND job_route_enabled = 1 AND job_route_job = ${jobDatabaseId}`); if (dbQuery) { if (dbQuery.numRows > 0) { while (dbAssoc = fetchQueryAssoc(dbQuery)) { let tempJobRouteData = new JobRouteData(dbAssoc); tempJobRouteData.locations = loadJobRouteLocationsFromDatabase(tempJobRouteData.databaseId); tempJobRoutes.push(tempJobRouteData); logToConsole(LOG_VERBOSE, `[VRR.Job]: Job route '${tempJobRouteData.name}' loaded from database successfully!`); } } freeDatabaseQuery(dbQuery); } disconnectFromDatabase(dbConnection); } logToConsole(LOG_DEBUG, `[VRR.Job]: ${tempJobRoutes.length} job routes for job ${jobDatabaseId} loaded from database successfully!`); return tempJobRoutes; } // =========================================================================== function loadJobRouteLocationsFromDatabase(jobRouteId) { logToConsole(LOG_DEBUG, `[VRR.Job]: Loading locations for job route ${jobRouteId} from database ...`); let tempJobRouteLocations = []; let dbConnection = connectToDatabase(); let dbQuery = null; let dbAssoc; if (dbConnection) { dbQuery = queryDatabase(dbConnection, `SELECT * FROM job_route_loc WHERE job_route_loc_deleted = 0 AND job_route_loc_enabled = 1 AND job_route_loc_route = ${jobRouteId}`); if (dbQuery) { if (dbQuery.numRows > 0) { while (dbAssoc = fetchQueryAssoc(dbQuery)) { let tempJobRouteLocationData = new JobRouteLocationData(dbAssoc); tempJobRouteLocations.push(tempJobRouteLocationData); logToConsole(LOG_VERBOSE, `[VRR.Job]: Job route location '${tempJobRouteLocationData.databaseId}' loaded from database successfully!`); } } freeDatabaseQuery(dbQuery); } disconnectFromDatabase(dbConnection); } logToConsole(LOG_DEBUG, `[VRR.Job]: ${tempJobRouteLocations.length} locations for job route ${jobRouteId} loaded from database successfully!`); return tempJobRouteLocations; } // =========================================================================== function loadJobEquipmentsFromDatabase(jobDatabaseId) { logToConsole(LOG_DEBUG, `[VRR.Job]: Loading job equipments for job ${jobDatabaseId} from database ...`); let tempJobEquipments = []; let dbConnection = connectToDatabase(); let dbQuery = null; let dbAssoc; if (dbConnection) { dbQuery = queryDatabase(dbConnection, `SELECT * FROM job_equip WHERE job_equip_deleted = 0 AND job_equip_enabled = 1 AND job_equip_job = ${jobDatabaseId}`); if (dbQuery) { if (dbQuery.numRows > 0) { while (dbAssoc = fetchQueryAssoc(dbQuery)) { let tempJobEquipmentData = new JobEquipmentData(dbAssoc); tempJobEquipmentData.items = loadJobEquipmentItemsFromDatabase(tempJobEquipmentData.databaseId); tempJobEquipments.push(tempJobEquipmentData); logToConsole(LOG_VERBOSE, `[VRR.Job]: Job equipment '${tempJobEquipmentData.name}' loaded from database successfully!`); } } freeDatabaseQuery(dbQuery); } disconnectFromDatabase(dbConnection); } logToConsole(LOG_DEBUG, `[VRR.Job]: ${tempJobEquipments.length} job equipments for job ${jobDatabaseId} loaded from database successfully!`); return tempJobEquipments; } // =========================================================================== function loadJobLocationsFromDatabase(jobDatabaseId) { logToConsole(LOG_DEBUG, `[VRR.Job]: Loading job locations for job ${jobDatabaseId} from database ...`); let tempJobLocations = []; let dbConnection = connectToDatabase(); let dbQuery = null; let dbAssoc; if (dbConnection) { dbQuery = queryDatabase(dbConnection, `SELECT * FROM job_loc WHERE job_loc_deleted = 0 AND job_loc_enabled = 1 AND job_loc_job = ${jobDatabaseId}`); if (dbQuery) { if (dbQuery.numRows > 0) { while (dbAssoc = fetchQueryAssoc(dbQuery)) { let tempJobLocationData = new JobLocationData(dbAssoc); tempJobLocations.push(tempJobLocationData); logToConsole(LOG_VERBOSE, `[VRR.Job]: Job location '${tempJobLocationData.databaseId}' loaded from database successfully!`); } } freeDatabaseQuery(dbQuery); } disconnectFromDatabase(dbConnection); } logToConsole(LOG_DEBUG, `[VRR.Job]: ${tempJobLocations.length} job locations for job ${jobDatabaseId} loaded from database successfully!`); return tempJobLocations; } // =========================================================================== function loadJobUniformsFromDatabase(jobDatabaseId) { logToConsole(LOG_DEBUG, `[VRR.Job]: Loading job uniforms for job ${jobDatabaseId} from database ...`); let tempJobUniforms = []; let dbConnection = connectToDatabase(); let dbQuery = null; let dbAssoc; if (dbConnection) { dbQuery = queryDatabase(dbConnection, "SELECT * FROM `job_uniform` WHERE `job_uniform_enabled` = 1 AND `job_uniform_job` = " + toString(jobDatabaseId)); if (dbQuery) { if (dbQuery.numRows > 0) { while (dbAssoc = fetchQueryAssoc(dbQuery)) { let tempJobUniformData = new JobUniformData(dbAssoc); tempJobUniforms.push(tempJobUniformData); logToConsole(LOG_VERBOSE, `[VRR.Job]: Job uniform '${tempJobUniformData.databaseId}' loaded from database successfully!`); } } freeDatabaseQuery(dbQuery); } disconnectFromDatabase(dbConnection); } logToConsole(LOG_DEBUG, `[VRR.Job]: ${tempJobUniforms.length} job uniforms for job ${jobDatabaseId} loaded from database successfully!`); return tempJobUniforms; } // =========================================================================== function loadJobEquipmentItemsFromDatabase(jobEquipmentDatabaseId) { logToConsole(LOG_DEBUG, `[VRR.Job]: Loading job equipment items for job equipment ${jobEquipmentDatabaseId} from database ...`); let tempJobEquipmentItems = []; let dbConnection = connectToDatabase(); let dbQuery = null; let dbAssoc; if (dbConnection) { dbQuery = queryDatabase(dbConnection, "SELECT * FROM `job_equip_item` WHERE `job_equip_item_enabled` = 1 AND `job_equip_item_equip` = " + toString(jobEquipmentDatabaseId)); if (dbQuery) { if (dbQuery.numRows > 0) { while (dbAssoc = fetchQueryAssoc(dbQuery)) { let tempJobEquipmentItemData = new JobEquipmentItemData(dbAssoc); tempJobEquipmentItems.push(tempJobEquipmentItemData); logToConsole(LOG_VERBOSE, `[VRR.Job]: Job equipment item '${tempJobEquipmentItemData.databaseId}' loaded from database successfully!`); } } freeDatabaseQuery(dbQuery); } disconnectFromDatabase(dbConnection); } logToConsole(LOG_DEBUG, `[VRR.Job]: ${tempJobEquipmentItems.length} job equipment items for equipment ${jobEquipmentDatabaseId} loaded from database successfully!`); return tempJobEquipmentItems; } // =========================================================================== function createAllJobBlips() { if (!getServerConfig().createJobBlips) { return false; } logToConsole(LOG_DEBUG, `[VRR.Job] Spawning all job location blips ...`); for (let i in getServerData().jobs) { for (let j in getServerData().jobs[i].locations) { createJobLocationBlip(i, j); } } logToConsole(LOG_DEBUG, `[VRR.Job] All job location blips spawned!`); } // =========================================================================== function createAllJobPickups() { if (!getServerConfig().createJobPickups) { return false; } logToConsole(LOG_DEBUG, `[VRR.Job] Spawning all job location pickups ...`); let pickupCount = 0; for (let i in getServerData().jobs) { if (getServerData().jobs[i].pickupModel != 0) { for (let j in getServerData().jobs[i].locations) { pickupCount++; getServerData().jobs[i].locations[j].pickup = game.createPickup(getServerData().jobs[i].pickupModel, getServerData().jobs[i].locations[j].position); setEntityData(getServerData().jobs[i].locations[j].pickup, "agrp.owner.type", AGRP_PICKUP_JOB, false); setEntityData(getServerData().jobs[i].locations[j].pickup, "agrp.owner.id", j, false); setEntityData(getServerData().jobs[i].locations[j].pickup, "agrp.label.type", AGRP_LABEL_JOB, true); setEntityData(getServerData().jobs[i].locations[j].pickup, "agrp.label.name", getServerData().jobs[i].name, true); setEntityData(getServerData().jobs[i].locations[j].pickup, "agrp.label.jobType", getServerData().jobs[i].databaseId, true); setElementOnAllDimensions(getServerData().jobs[i].locations[j].pickup, false); setElementDimension(getServerData().jobs[i].locations[j].pickup, getServerData().jobs[i].locations[j].dimension); addToWorld(getServerData().jobs[i].locations[j].pickup); logToConsole(LOG_VERBOSE, `[VRR.Job] Job '${getServerData().jobs[i].name}' location pickup ${j} spawned!`); } } } logToConsole(LOG_DEBUG, `[VRR.Job] All job location pickups (${pickupCount}) spawned!`); } // =========================================================================== function showJobInformationToPlayer(client, jobType) { if (!canPlayerUseJobs(client)) { return false; } if (jobType == getPlayerCurrentSubAccount(client).job) { messagePlayerInfo("Welcome back to your job. Use /startwork to begin."); return false; } switch (jobType) { case AGRP_JOB_POLICE: if (!canPlayerUsePoliceJob(client)) { return false; } messagePlayerInfo(client, "== Job Help ================================="); messagePlayerInfo(client, "- Police Officers are enforcers of the law."); messagePlayerInfo(client, "- Use /startwork at a police station to work as a Police Officer."); messagePlayerInfo(client, "- Use /laws to see a list of laws."); messagePlayerInfo(client, "- Commands are: /cuff, /drag, /detain, /arrest, /search /tazer /radio"); messagePlayerInfo(client, "- When finished, use /stopwork to stop working."); break; case AGRP_JOB_MEDICAL: messagePlayerInfo(client, "== Job Help ================================="); messagePlayerInfo(client, "- Paramedics help people by healing them."); messagePlayerInfo(client, "- Use /startwork at the hospital to work as a Paramedic."); messagePlayerInfo(client, "- People can enter your ambulance to get healed."); messagePlayerInfo(client, "- The pay depends on the player's health before healing them."); messagePlayerInfo(client, "- When finished, use /stopwork to stop working."); break; case AGRP_JOB_FIRE: if (!canClientUseFireJob(client)) { return false; } messagePlayerInfo(client, "== Job Help ================================="); messagePlayerInfo(client, "- Firefighters put out vehicle and building fires."); messagePlayerInfo(client, "- Use /startwork at the fire station to work as a Firefighter."); messagePlayerInfo(client, "- Get in a firetruck and you will be told where to go."); messagePlayerInfo(client, "- Use the firetruck hose to put out fires"); messagePlayerInfo(client, "- When finished, use /stopwork to stop working."); break; case AGRP_JOB_BUS: messagePlayerInfo(client, "== Job Help ================================="); messagePlayerInfo(client, "- Bus Drivers transport people around the city on a route"); messagePlayerInfo(client, "- Use /startwork at the bus depot to work as a Bus Driver."); messagePlayerInfo(client, "- Passengers can get on/off at any stop on your route"); messagePlayerInfo(client, "- Stay on your assigned route. You will be paid when finished."); messagePlayerInfo(client, "- When finished, use /stopwork to stop working."); break; case AGRP_JOB_TAXI: messagePlayerInfo(client, "== Job Help ================================="); messagePlayerInfo(client, "- Taxi Drivers transport people around the city"); messagePlayerInfo(client, "- Use /startwork at the taxi depot to work as a Taxi Driver."); messagePlayerInfo(client, "- Use /fare to set a fare. Fares start when a player gets in."); messagePlayerInfo(client, "- The meter will run until the player exits the vehicle."); messagePlayerInfo(client, "- You will automatically receive the fare money"); messagePlayerInfo(client, "- When finished, use /stopwork to stop working."); break; case AGRP_JOB_GARBAGE: messagePlayerInfo(client, "== Job Help ================================="); messagePlayerInfo(client, "- Garbage Collectors pick up the trash around the city."); messagePlayerInfo(client, "- Use /startwork at the garbage depot to work as a Garbage Collector."); messagePlayerInfo(client, "- Drive up to a garbage can or dumpster, and right click to grab a bag."); messagePlayerInfo(client, "- Walk up to the back of your truck and right click again to throw the bag in."); messagePlayerInfo(client, "- Your truck can hold 25 trashbags. Each bag is worth $25"); messagePlayerInfo(client, "- Drive to the garbage depot again to deliver trash"); messagePlayerInfo(client, "- When finished, use /stopwork to stop working."); break; case AGRP_JOB_WEAPON: break; case AGRP_JOB_DRUG: break; default: break; } } // =========================================================================== function jobListCommand(command, params, client) { if (!canPlayerUseJobs(client)) { messagePlayerError(client, "You are not allowed to use any jobs!"); return false; } let jobList = getServerData().jobs.map(function (x) { return `[${hexFromToColour(x.colour)}]${x.name}{MAINCOLOUR}` }); let chunkedList = splitArrayIntoChunks(jobList, 4); messagePlayerNormal(client, makeChatBoxSectionHeader(getLocaleString(client, "HeaderJobList"))); for (let i in chunkedList) { messagePlayerInfo(client, chunkedList[i].join(", ")); } return true; } // =========================================================================== function takeJobCommand(command, params, client) { if (!canPlayerUseJobs(client)) { messagePlayerError(client, "You are not allowed to use any jobs!"); return false; } let closestJobLocation = getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)); let jobData = getJobData(closestJobLocation.jobIndex); if (closestJobLocation.position.distance(getPlayerPosition(client)) > getGlobalConfig().takeJobDistance) { messagePlayerError(client, "There are no job points close enough!"); return false; } if (getPlayerCurrentSubAccount(client).job > AGRP_JOB_NONE) { messagePlayerInfo(client, getLocaleString(client, "QuitJobToTakeAnother", "{ALTCOLOUR}/quitjob{MAINCOLOUR}")); return false; } if (!canPlayerUseJob(client, closestJobLocation.jobIndex)) { messagePlayerError(client, "You can't use this job!"); return false; } takeJob(client, closestJobLocation.jobIndex); messagePlayerSuccess(client, `{MAINCOLOUR}You now have the {jobYellow}${jobData.name} {MAINCOLOUR}job`); return true; } // =========================================================================== function startWorkingCommand(command, params, client) { if (!canPlayerUseJobs(client)) { return false; } let closestJobLocation = getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)); let jobData = false; if (closestJobLocation.position.distance(getPlayerPosition(client)) > getGlobalConfig().startWorkingDistance) { let closestVehicle = getClosestVehicle(getPlayerPosition(client)); if (getDistance(getVehiclePosition(closestVehicle), getPlayerPosition(client)) > getGlobalConfig().startWorkingDistance) { messagePlayerError(client, "You need to be near your job site or vehicle that belongs to your job!"); return false; } if (getVehicleData(closestVehicle).ownerType != AGRP_VEHOWNER_JOB) { messagePlayerError(client, getLocaleString(client, "NotAJobVehicle")); return false; } if (getPlayerCurrentSubAccount(client).job != getVehicleData(closestVehicle).ownerId) { messagePlayerError(client, getLocaleString(client, "NotYourJobVehicle")); return false; } jobData = getJobData(getJobIdFromDatabaseId(getVehicleData(closestVehicle).ownerId)); } else { if (getPlayerCurrentSubAccount(client).job == AGRP_JOB_NONE) { messagePlayerError(client, "You don't have a job!"); messagePlayerInfo(client, "You can get a job by going the yellow points on the map."); return false; } if (getPlayerCurrentSubAccount(client).job != closestJobLocation.jobId) { messagePlayerError(client, "This is not your job!"); messagePlayerInfo(client, getLocaleString(client, "QuitJobToTakeAnother", "{ALTCOLOUR}/quitjob{MAINCOLOUR}")); return false; } jobData = getJobData(closestJobLocation.jobIndex); } if (!jobData.enabled) { messagePlayerError(client, getLocaleString(client, "JobDisabled", jobData.name)); return false; } messagePlayerSuccess(client, `💼 You are now working for the {jobYellow}${jobData.name}{MAINCOLOUR} job`); messageDiscordEventChannel(`💼 ${getCharacterFullName(client)} started working for the {jobYellow}${jobData.name}{MAINCOLOUR} job`); startWorking(client); //messagePlayerNewbieTip(client, `Enter a job vehicle to get started!`); return true; } // =========================================================================== function stopWorkingCommand(command, params, client) { if (!canPlayerUseJobs(client)) { return false; } if (!isPlayerWorking(client)) { messagePlayerError(client, "You are not working!"); return false; } deleteJobItems(client); stopWorking(client); messagePlayerSuccess(client, "You have stopped working!"); return true; } // =========================================================================== function startWorking(client) { if (!canPlayerUseJobs(client)) { return false; } switchPlayerActiveHotBarSlot(client, -1); getPlayerCurrentSubAccount(client).skin = getPlayerSkin(client); storePlayerItemsInTempLocker(client); getPlayerData(client).tempLockerType = AGRP_TEMP_LOCKER_TYPE_JOB; messagePlayerInfo(client, "Your personal items have been stored in your locker while you work"); getPlayerCurrentSubAccount(client).isWorking = true; let jobId = getPlayerCurrentSubAccount(client).job; switch (getJobIndexFromDatabaseId(jobId)) { case AGRP_JOB_POLICE: messagePlayerInfo(client, getLocaleString(client, "JobEquipAndUniformLabel", `{ALTCOLOUR}/uniform{MAINCOLOUR}, {ALTCOLOUR}/equip{MAINCOLOUR}`)); break; case AGRP_JOB_MEDICAL: messagePlayerInfo(client, getLocaleString(client, "JobEquipAndUniformLabel", `{ALTCOLOUR}/uniform{MAINCOLOUR}, {ALTCOLOUR}/equip{MAINCOLOUR}`)); break; case AGRP_JOB_FIRE: messagePlayerInfo(client, getLocaleString(client, "JobEquipAndUniformLabel", `{ALTCOLOUR}/uniform{MAINCOLOUR}, {ALTCOLOUR}/equip{MAINCOLOUR}`)); break; case AGRP_JOB_BUS: messagePlayerInfo(client, getLocaleString(client, "GetStartedJobVehicle", getGroupedLocaleString(client, "VehicleTypes", "Bus"))); break; case AGRP_JOB_TAXI: messagePlayerInfo(client, getLocaleString(client, "GetStartedJobVehicle", getGroupedLocaleString(client, "VehicleTypes", "Taxi"))); break; case AGRP_JOB_GARBAGE: messagePlayerInfo(client, getLocaleString(client, "GetStartedJobVehicle", getGroupedLocaleString(client, "VehicleTypes", "GarbageTruck"))); break; case AGRP_JOB_WEAPON: break; case AGRP_JOB_DRUG: break; default: break; } updatePlayerNameTag(client); sendPlayerWorkingState(client, true); //showStartedWorkingTip(client); } // =========================================================================== function getJobInfoCommand(command, params, client) { let closestJobLocation = getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)); messagePlayerInfo(client, `{jobYellow}[Job Info] {MAINCOLOUR}Name: {ALTCOLOUR}${getJobData(closestJobLocation.jobIndex).name}, {MAINCOLOUR}Enabled: {ALTCOLOUR}${getYesNoFromBool(intToBool(getJobData(closestJobLocation.jobIndex).enabled))}, {MAINCOLOUR}Whitelisted: {ALTCOLOUR}${getYesNoFromBool(intToBool(getJobData(closestJobLocation.jobIndex).whiteListEnabled))}, {MAINCOLOUR}Blacklisted: {ALTCOLOUR}${getYesNoFromBool(intToBool(getJobData(closestJobLocation.jobIndex).blackListEnabled))}, {MAINCOLOUR}ID: {ALTCOLOUR}${getJobData(closestJobLocation.jobIndex).databaseId}/${closestJobLocation.jobIndex}`); } // =========================================================================== function getJobLocationInfoCommand(command, params, client) { let closestJobLocation = getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)); messagePlayerInfo(client, `{jobYellow}[Job Location Info] {MAINCOLOUR}Job: {ALTCOLOUR}${getJobData(closestJobLocation.jobIndex).name} (${getJobData(closestJobLocation.jobIndex).databaseId}/${closestJobLocation.jobIndex}), {MAINCOLOUR}Enabled: {ALTCOLOUR}${getYesNoFromBool(closestJobLocation.enabled)}, {MAINCOLOUR}Database ID: {ALTCOLOUR}${closestJobLocation.databaseId}`); } // =========================================================================== function givePlayerJobEquipment(client, equipmentId) { if (!canPlayerUseJobs(client)) { return false; } if (!doesPlayerHaveAnyJob(client)) { return false; } let jobId = getPlayerJob(client); for (let i in getJobData(jobId).equipment[equipmentId].items) { let value = getJobData(jobId).equipment[equipmentId].items[i].value if (getItemTypeData(getItemTypeIndexFromDatabaseId(getJobData(jobId).equipment[equipmentId].items[i].itemType)).useType == AGRP_ITEM_USE_TYPE_WALKIETALKIE) { value = getJobData(jobId).walkieTalkieFrequency; } let itemId = createItem(getItemTypeIndexFromDatabaseId(getJobData(jobId).equipment[equipmentId].items[i].itemType), value, AGRP_ITEM_OWNER_PLAYER, getPlayerCurrentSubAccount(client).databaseId); getItemData(itemId).needsSaved = false; getItemData(itemId).databaseId = -1; // Make sure it doesnt save let freeSlot = getPlayerFirstEmptyHotBarSlot(client); getPlayerData(client).hotBarItems[freeSlot] = itemId; getPlayerData(client).jobEquipmentCache.push(itemId); updatePlayerHotBar(client); } switchPlayerActiveHotBarSlot(client, -1); } // =========================================================================== function stopWorking(client) { if (!canPlayerUseJobs(client)) { return false; } if (!doesPlayerHaveAnyJob(client)) { return false; } if (!isPlayerWorking(client)) { return false; } getPlayerCurrentSubAccount(client).isWorking = false; setPlayerSkin(client, getPlayerCurrentSubAccount(client).skin); let jobVehicle = getPlayerData(client).lastJobVehicle; if (jobVehicle) { if (getPlayerVehicle(client) == jobVehicle) { removePlayerFromVehicle(client); //getPlayerPed(client).removeFromVehicle(); } respawnVehicle(jobVehicle); getPlayerData(client).lastJobVehicle = false; } setPlayerSkin(client, getPlayerCurrentSubAccount(client).skin); deleteJobItems(client); restorePlayerTempLockerItems(client); respawnJobVehicle(client); sendPlayerStopJobRoute(client); let jobId = getPlayerJob(client); messageDiscordEventChannel(`💼 ${getCharacterFullName(client)} has stopped working as a ${getJobData(jobId).name}`); switch (getJobType(jobId)) { case AGRP_JOB_POLICE: messagePlayerInfo(client, "Your uniform, equipment, and vehicle have been returned to the police station"); break; case AGRP_JOB_MEDICAL: messagePlayerInfo(client, "Your uniform, equipment, and vehicle have been returned to the hospital"); break; case AGRP_JOB_FIRE: messagePlayerInfo(client, "Your uniform, equipment, and vehicle have been returned to the fire station"); break; case AGRP_JOB_BUS: messagePlayerInfo(client, "Your vehicle has been returned to the bus depot"); break; case AGRP_JOB_TAXI: messagePlayerInfo(client, "Your vehicle has been returned to the taxi depot"); break; case AGRP_JOB_GARBAGE: messagePlayerInfo(client, "Your vehicle has been returned to the city trash dump"); break; case AGRP_JOB_WEAPON: break; case AGRP_JOB_DRUG: break; case AGRP_JOB_GENERIC: messagePlayerInfo(client, "Your vehicle has been respawned at your job location"); break; default: break; } updatePlayerNameTag(client); sendPlayerWorkingState(client, false); //cachePlayerHotBarItems(client); // Done in restorePlayerTempLockerItems } // =========================================================================== function jobUniformCommand(command, params, client) { if (!canPlayerUseJobs(client)) { return false; } if (!doesPlayerHaveAnyJob(client)) { messagePlayerError(client, "You don't have a job!"); return false; } if (!isPlayerWorking(client)) { messagePlayerError(client, "You are not working! Use /startwork at your job location or a job vehicle."); return false; } let closestJobLocation = getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)); let jobData = false; if (closestJobLocation.position.distance(getPlayerPosition(client)) > getGlobalConfig().startWorkingDistance) { let closestVehicle = getClosestVehicle(getPlayerPosition(client)); if (getDistance(getVehiclePosition(closestVehicle), getPlayerPosition(client)) > getGlobalConfig().startWorkingDistance) { messagePlayerError(client, "You need to be near your job site or vehicle that belongs to your job!"); return false; } if (getVehicleData(closestVehicle).ownerType != AGRP_VEHOWNER_JOB) { messagePlayerError(client, getLocaleString(client, "NotAJobVehicle")); return false; } if (getPlayerCurrentSubAccount(client).job != getVehicleData(closestVehicle).ownerId) { messagePlayerError(client, getLocaleString(client, "NotYourJobVehicle")); return false; } jobData = getJobData(getJobIdFromDatabaseId(getVehicleData(closestVehicle).ownerId)); } else { if (getPlayerCurrentSubAccount(client).job == AGRP_JOB_NONE) { messagePlayerError(client, getLocaleString(client, "NotYourJob")); messagePlayerInfo(client, getLocaleString(client, "JobPoints")); return false; } if (getPlayerCurrentSubAccount(client).job != closestJobLocation.jobId) { messagePlayerError(client, getLocaleString(client, "NotYourJob")); messagePlayerInfo(client, getLocaleString(client, "QuitJobToTakeAnother", "{ALTCOLOUR}/quitjob{MAINCOLOUR}")); return false; } jobData = getJobData(closestJobLocation.jobIndex); } if (!jobData.enabled) { messagePlayerError(client, getLocaleString(client, "JobDisabled", jobData.name)); return false; } let uniforms = jobData.uniforms; if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); let uniformList = jobData.uniforms.map(function (x) { return `{MAINCOLOUR}${toInteger(x.index) + 1}: {ALTCOLOUR}${x.name}` }); let chunkedList = splitArrayIntoChunks(uniformList, 4); messagePlayerNormal(client, makeChatBoxSectionHeader(getLocaleString(client, "HeaderJobUniformList"))); for (let i in chunkedList) { messagePlayerInfo(client, chunkedList[i].join(", ")); } return false; } let jobIndex = getPlayerJob(client); let rankIndex = getPlayerJobRank(client); let uniformId = toInteger(params) || 1; let jobRankData = getJobRankData(jobIndex, rankIndex); if (uniformId == 0) { setPlayerSkin(client, getPlayerCurrentSubAccount(client).skin); meActionToNearbyPlayers(client, `takes off their uniform`); return false; } if (uniformId < 1 || uniformId > uniforms.length) { messagePlayerError(client, getLocaleString(client, "InvalidJobUniform")); return false; } let uniformData = getJobUniformData(jobIndex, uniformId - 1); if (jobData.ranks.length > 0) { if (jobRankData.level < uniformData.requiredRank) { messagePlayerError(client, getLocaleString(client, "JobRankTooLow", jobRankData.level, uniformData.requiredRank)); return false; } } setPlayerSkin(client, uniformData.skin); meActionToNearbyPlayers(client, `puts on ${getProperDeterminerForName(uniformData.name)} ${uniformData.name} uniform`); } // =========================================================================== function jobEquipmentCommand(command, params, client) { if (!canPlayerUseJobs(client)) { return false; } if (!doesPlayerHaveAnyJob(client)) { messagePlayerError(client, "You don't have a job!"); return false; } if (!isPlayerWorking(client)) { messagePlayerError(client, "You are not working! Use /startwork at your job location."); return false; } let closestJobLocation = getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)); let jobData = false; if (closestJobLocation.position.distance(getPlayerPosition(client)) > getGlobalConfig().startWorkingDistance) { let closestVehicle = getClosestVehicle(getPlayerPosition(client)); if (getDistance(getVehiclePosition(closestVehicle), getPlayerPosition(client)) > getGlobalConfig().startWorkingDistance) { messagePlayerError(client, "You need to be near your job site or vehicle that belongs to your job!"); return false; } if (getVehicleData(closestVehicle).ownerType != AGRP_VEHOWNER_JOB) { messagePlayerError(client, getLocaleString(client, "NotAJobVehicle")); return false; } if (getPlayerCurrentSubAccount(client).job != getVehicleData(closestVehicle).ownerId) { messagePlayerError(client, getLocaleString(client, "NotYourJobVehicle")); return false; } jobData = getJobData(getJobIdFromDatabaseId(getVehicleData(closestVehicle).ownerId)); } else { if (getPlayerCurrentSubAccount(client).job == AGRP_JOB_NONE) { messagePlayerError(client, getLocaleString(client, "NotYourJob")); messagePlayerInfo(client, getLocaleString(client, "JobPoints")); return false; } if (getPlayerCurrentSubAccount(client).job != closestJobLocation.jobId) { messagePlayerError(client, "This is not your job!"); messagePlayerInfo(client, getLocaleString(client, "QuitJobToTakeAnother", "{ALTCOLOUR}/quitjob{MAINCOLOUR}")); return false; } jobData = getJobData(closestJobLocation.jobIndex); } if (!jobData.enabled) { messagePlayerError(client, getLocaleString(client, "JobDisabled", jobData.name)); return false; } let equipments = jobData.equipment; if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); messagePlayerNormal(client, `0: No equipment`); for (let i in equipments) { messagePlayerNormal(client, `${toInteger(i) + 1}: ${equipments[i].name} (Requires rank ${equipments[i].requiredRank})`); } return false; } let jobIndex = getPlayerJob(client); let rankIndex = getPlayerJobRank(client); let equipmentId = toInteger(params) || 1; let jobRankData = getJobRankData(jobIndex, rankIndex); if (equipmentId == 0) { meActionToNearbyPlayers(client, `puts their equipment into the locker`); deleteJobItems(client); return true; } if (equipmentId < 1 || equipmentId > equipments.length) { messagePlayerError(client, "That equipment ID is invalid!"); return false; } let jobEquipmentData = getJobEquipmentData(jobIndex, equipmentId - 1) if (jobData.ranks.length > 0) { if (jobRankData.level < jobEquipmentData.requiredRank) { messagePlayerError(client, getLocaleString(client, "JobRankTooLow", jobRankData.level, jobEquipmentData.requiredRank)); return false; } } deleteJobItems(client); givePlayerJobEquipment(client, equipmentId - 1); //messagePlayerSuccess(client, `You have been given the ${equipments[equipmentId-1].name} equipment`); meActionToNearbyPlayers(client, `grabs the ${jobEquipmentData.name} equipment from the locker`); if (!hasPlayerSeenActionTip(client, "JobEquipmentInventory")) { if (doesPlayerHaveKeyBindForCommand(client, "inv")) { messagePlayerTip(client, getIndexedLocaleString(client, "ActionTips", "JobEquipmentInventory", toUpperCase(getKeyNameFromId(getPlayerKeyBindForCommand(client, "inv").key)))); } else { messagePlayerTip(client, getIndexedLocaleString(client, "ActionTips", "JobEquipmentInventory", "/inv")); } markPlayerActionTipSeen(client, "JobEquipmentInventory"); } } // =========================================================================== function quitJobCommand(command, params, client) { if (!canPlayerUseJobs(client)) { return false; } if (!doesPlayerHaveAnyJob(client)) { return false; } stopWorking(client); quitJob(client); messagePlayerSuccess(client, "You are now unemployed!"); return true; } // =========================================================================== function jobRadioCommand(command, params, client) { if (!canPlayerUseJobs(client)) { return false; } return true; } // =========================================================================== function jobDepartmentRadioCommand(command, params, client) { if (!canPlayerUseJobs(client)) { return false; } return true; } // =========================================================================== function getJobType(jobId) { return getJobData(jobId).type; } // =========================================================================== function doesPlayerHaveJobType(client, jobType) { return (getJobType(getJobIdFromDatabaseId(getPlayerCurrentSubAccount(client).job)) == jobType) ? true : false; } // =========================================================================== /** * @param {number} jobIndex - The data index of the job * @return {JobData} The job's data (class instance) */ function getJobData(jobId) { if (typeof getServerData().jobs[jobId] != "undefined") { return getServerData().jobs[jobId]; } return false; } // =========================================================================== function quitJob(client) { stopWorking(client); getPlayerCurrentSubAccount(client).job = 0; getPlayerCurrentSubAccount(client).jobRank = 0; getPlayerCurrentSubAccount(client).jobIndex = -1; getPlayerCurrentSubAccount(client).jobRankIndex = -1; sendPlayerJobType(client, 0); updateJobBlipsForPlayer(client); } // =========================================================================== function takeJob(client, jobId) { let rankIndex = -1; let rankId = 0; if (getJobData(jobId).ranks.length > 0) { rankIndex = getLowestJobRank(jobId); rankId = getJobRankData(jobId, rankId).databaseId; } getPlayerCurrentSubAccount(client).job = getJobData(jobId).databaseId; getPlayerCurrentSubAccount(client).jobRank = rankId; getPlayerCurrentSubAccount(client).jobIndex = jobId; getPlayerCurrentSubAccount(client).jobRankIndex = rankIndex; sendPlayerJobType(client, getJobData(jobId).databaseId); updateJobBlipsForPlayer(client); } // =========================================================================== function reloadAllJobsCommand(command, params, client) { forceAllPlayersToStopWorking(); deleteAllJobBlips(); deleteAllJobPickups(); clearArray(getServerData().jobs); Promise.resolve().then(() => { getServerData().jobs = loadJobsFromDatabase(); createAllJobPickups(); createAllJobBlips(); }); announceAdminAction("AllJobsReloaded"); } // =========================================================================== function createJobCommand(command, params, client) { createJob(params); messagePlayerSuccess(client, `Job {jobYellow}${params} {MAINCOLOUR}created!`); return true; } // =========================================================================== function createJob(name) { let tempJobData = new JobData(false); tempJobData.serverId = getServerId(); tempJobData.name = name; tempJobData.enabled = true; tempJobData.needsSaved = true; tempJobData.blipModel = getGameConfig().blipSprites[getGame()].Job; tempJobData.pickupModel = getGameConfig().pickupModels[getGame()].Job; tempJobData.colour = toColour(255, 255, 255, 255); getServerData().jobs.push(tempJobData); saveJobToDatabase(tempJobData); setAllJobDataIndexes(); } // =========================================================================== function createJobLocationCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getJobFromParams(params); if (!getJobData(jobId)) { messagePlayerError(client, "That job was not found!"); return false; } createJobLocation(jobId, getPlayerPosition(client), getPlayerInterior(client), getPlayerDimension(client)); messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} created a location for the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job`); return true; } // =========================================================================== function deleteJobLocationCommand(command, params, client) { let closestJobLocation = getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)); messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} deleted location {ALTCOLOUR}${closestJobLocation.index} (DB ID ${closestJobLocation.databaseId}){MAINCOLOUR} for the {jobYellow}${getJobData(closestJobLocation.jobIndex).name}{MAINCOLOUR} job`); deleteJobLocation(closestJobLocation); } // =========================================================================== function toggleJobLocationEnabledCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let closestJobLocation = getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)); closestJobLocation.enabled = !closestJobLocation.enabled; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} ${getEnabledDisabledFromBool(closestJobLocation.enabled)} location {ALTCOLOUR}${closestJobLocation.databaseId} {MAINCOLOUR}for the {jobYellow}${getJobData(closestJobLocation.jobIndex).name}{MAINCOLOUR} job`); } // =========================================================================== function toggleJobEnabledCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getJobFromParams(params) || getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)).jobIndex; getJobData(jobId).enabled = !getJobData(jobId).enabled; messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR}${getEnabledDisabledFromBool(getJobData(jobId).enabled)}{MAINCOLOUR} the {jobYellow}${getJobData(jobId).name} {MAINCOLOUR}job`); } // =========================================================================== function createJobUniform(jobId, skinIndex, rankLevel) { let tempJobUniformData = new JobUniformData(false); tempJobUniformData.skin = skinIndex; tempJobUniformData.job = getJobData(jobId).databaseId; tempJobUniformData.jobIndex = jobId; tempJobUniformData.requiredRank = rankLevel; getJobData(jobId).uniforms.push(tempJobUniformData); return true; } // =========================================================================== function setJobColourCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } if (!areThereEnoughParams(params, 4, " ")) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)).jobIndex; let red = getParam(params, " ", 2) || 255; let green = getParam(params, " ", 3) || 255; let blue = getParam(params, " ", 4) || 255; getJobData(jobId).colour = toColour(toInteger(red), toInteger(green), toInteger(blue), 255); getJobData(jobId).needsSaved = true; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set job {jobYellow}${getJobData(jobId).name}'s{MAINCOLOUR} colour to ${red}, ${green}, ${blue}`); // Force nametag update in case somebody is using this job updateAllPlayerNameTags(); } // =========================================================================== function setJobBlipCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } if (!areThereEnoughParams(params, 2, " ")) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getJobFromParams(getParam(params, " ", 1)) || getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)).jobIndex; let blipParam = getParam(params, " ", 2); let blipId = getJobData(jobId).blipModel; let blipString = "unchanged"; if (isNaN(blipParam)) { if (toLowerCase(blipParam) == "none") { blipId = -1; } else { if (isNull(getGameConfig().blipSprites[getGame()][blipParam])) { let blipTypes = Object.keys(getGameConfig().blipSprites[getGame()]); let chunkedList = splitArrayIntoChunks(blipTypes, 10); messagePlayerNormal(client, makeChatBoxSectionHeader(getLocaleString(client, "HeaderBlipTypes"))); for (let i in chunkedList) { messagePlayerInfo(client, chunkedList[i].join(", ")); } } else { blipId = getGameConfig().blipSprites[getGame()][blipParam]; blipString = toString(blipParam); } } } else { blipId = toInteger(blipParam); blipString = toString(blipId); } getJobData(jobId).blipModel = blipId; getJobData(jobId).needsSaved = true; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set job {jobYellow}${getJobData(jobId).name}'s{MAINCOLOUR} blip model to ${blipString}`); resetAllJobBlips(); } // =========================================================================== function setJobPickupCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } if (!areThereEnoughParams(params, 2, " ")) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getJobFromParams(getParam(params, " ", 1)) || getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)).jobIndex; let pickupParam = getParam(params, " ", 2); let pickupId = getJobData(jobId).pickupModel; let pickupString = "none"; if (isNaN(pickupParam)) { if (toLowerCase(pickupParam) == "none") { pickupId = -1; } else { if (isNull(getGameConfig().pickupModels[getGame()][pickupParam])) { messagePlayerError(client, "Invalid pickup type! Use a pickup type name or a model ID"); let pickupTypes = Object.keys(getGameConfig().pickupModels[getGame()]); let chunkedList = splitArrayIntoChunks(pickupTypes, 10); messagePlayerNormal(client, makeChatBoxSectionHeader(getLocaleString(client, "HeaderPickupTypes"))); for (let i in chunkedList) { messagePlayerInfo(client, chunkedList[i].join(", ")); } return false; } else { pickupId = getGameConfig().pickupModels[getGame()][pickupParam]; pickupString = toString(pickupParam); } } } else { pickupId = toInteger(pickupParam); pickupString = toString(pickupId); } getJobData(jobId).pickupModel = pickupId; getJobData(jobId).needsSaved = true; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set job {jobYellow}${getJobData(jobId).name}'s{MAINCOLOUR} pickup to ${pickupString}`); resetAllJobPickups(); } // =========================================================================== function toggleJobRouteEnabledCommand(command, params, client) { let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); let clients = getClients(); for (let i in clients) { if (isPlayerWorking(clients[i])) { if (isPlayerOnJobRoute(clients[i])) { if (getPlayerJob(clients[i]) == jobId && getPlayerJobRoute(clients[i]) == jobRoute) { stopJobRoute(clients[i], true, false); messagePlayerAlert(clients[i], "The job route you were on has been disabled by an admin"); } } } } getJobData(jobId).routes[jobRoute].enabled = !getJobData(jobId).routes[jobRoute].enabled; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} ${getEnabledDisabledFromBool(getJobRouteData(jobId, jobRoute).enabled)} route {ALTCOLOUR}${getJobRouteData(jobId, jobRoute).name}{MAINCOLOUR} for the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job`); } // =========================================================================== function setJobRouteNameCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); let oldName = getJobData(jobId).routes[jobRoute].name; getJobData(jobId).routes[jobRoute].name = params; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set route {ALTCOLOUR}${oldName}{MAINCOLOUR} to {ALTCOLOUR}${getJobRouteData(jobId, jobRoute).name}{MAINCOLOUR} for the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job`); } // =========================================================================== function setJobRouteAllLocationDelaysCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); let delay = getParam(params, " ", 1); if (isNaN(delay)) { messagePlayerError(client, getLocaleString(client, "TimeNotNumber")) return false; } for (let i in getJobData(jobId).routes[jobRoute].locations) { getJobData(jobId).routes[jobRoute].locations[i].stopDelay = toInteger(delay); getJobData(jobId).routes[jobRoute].locations[i].needsSaved = true; } messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set route {ALTCOLOUR}${getJobData(jobId).routes[jobRoute].name}{MAINCOLOUR} location's stop delays to {ALTCOLOUR}${delay / 1000}{MAINCOLOUR} seconds for the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job`); } // =========================================================================== function setJobRouteNextLocationDelayCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); let delay = getParam(params, " ", 1); if (isNaN(delay)) { messagePlayerError(client, getLocaleString(client, "TimeNotNumber")) return false; } getPlayerData(client).jobRouteEditNextLocationDelay = delay; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set the stop delay to {ALTCOLOUR}${delay / 1000}{MAINCOLOUR} seconds for the next location on route {ALTCOLOUR}${getJobData(jobId).routes[jobRoute].name}{MAINCOLOUR} for the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job`); } // =========================================================================== function setJobRouteNextLocationArriveMessageCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); let message = params; getPlayerData(client).jobRouteEditNextLocationArriveMessage = message; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set the arrival message for the next location on route {ALTCOLOUR}${getJobData(jobId).routes[jobRoute].name}{MAINCOLOUR} for the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job to {ALTCOLOUR}"${message}"{MAINCOLOUR}`); } // =========================================================================== function setJobRouteNextLocationGotoMessageCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); let message = params; getPlayerData(client).jobRouteEditNextLocationGotoMessage = message; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set the goto message for the next location on route {ALTCOLOUR}${getJobData(jobId).routes[jobRoute].name}{MAINCOLOUR} for the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job to {ALTCOLOUR}"${message}"{MAINCOLOUR}`); } // =========================================================================== function setJobRouteNextLocationTypeCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); let typeId = getJobRouteLocationTypeFromParams(params); if (typeId == -1) { messagePlayerError(client, `{MAINCOLOUR}${params}{ALTCOLOUR} is not a valid job route location type`); let nameList = jobRouteLocationTypeNames.map((jobRouteLocationTypeName) => { return jobRouteLocationTypeName[0]; }); messagePlayerInfo(client, `{MAINCOLOUR}Available location types: {ALTCOLOUR}${nameList.join(", ")}{MAINCOLOUR}`); return false; } getPlayerData(client).jobRouteEditNextLocationType = type; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set the type for the next location on route {ALTCOLOUR}${getJobData(jobId).routes[jobRoute].name}{MAINCOLOUR} for the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job to {ALTCOLOUR}${getJobRouteLocationTypeName(typeId)}{MAINCOLOUR}`); } // =========================================================================== function setJobRouteVehicleColoursCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); let colour1 = getParam(params, " ", 1); let colour2 = getParam(params, " ", 2); getJobRouteData(getPlayerJob(client), getPlayerJobRoute(client)).vehicleColour1 = toInteger(colour1); getJobRouteData(getPlayerJob(client), getPlayerJobRoute(client)).vehicleColour2 = toInteger(colour2); getJobRouteData(getPlayerJob(client), getPlayerJobRoute(client)).needsSaved = true; let clients = getClients(); for (let i in clients) { if (isPlayerWorking(clients[i])) { if (isPlayerOnJobRoute(clients[i])) { if (getPlayerJob(clients[i]) == jobId && getPlayerJobRoute(clients[i]) == jobRoute) { setVehicleColours(getPlayerVehicle(clients[i]), toInteger(colour1), toInteger(colour2), 1, 1); messagePlayerAlert(clients[i], getLocaleString(client, "CurrentJobRouteVehicleColoursChanged")); } } } } messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set the vehicle colours to {ALTCOLOUR}${colour1}, ${colour2}{MAINCOLOUR} for route {ALTCOLOUR}${getJobRouteData(jobId, jobRoute).name} {MAINCOLOUR} of the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job`); } // =========================================================================== function setJobRouteFinishMessageCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); getJobData(jobId).routes[jobRoute].finishMessage = params; getJobData(jobId).routes[jobRoute].needsSaved = true; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set the finish message to {ALTCOLOUR}"${params}"{MAINCOLOUR} for route {ALTCOLOUR}${getJobRouteData(jobId, jobRoute).name}{MAINCOLOUR} of the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job`); } // =========================================================================== function setJobRouteStartMessageCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); getJobData(jobId).routes[jobRoute].startMessage = params; getJobData(jobId).routes[jobRoute].needsSaved = true; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set the start message to {ALTCOLOUR}"${params}"{MAINCOLOUR} for route {ALTCOLOUR}${getJobRouteData(jobId, jobRoute).name}{MAINCOLOUR} of the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job`); } // =========================================================================== function setJobRouteLocationPositionCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); let jobRouteLocation = getPlayerJobRouteLocation(client); getJobData(jobId).routes[jobRoute].locations[jobRouteLocation].position = position; getJobData(jobId).routes[jobRoute].locations[jobRouteLocation].needsSaved = true; showCurrentJobLocation(client); messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR} ${getEnabledDisabledFromBool(getJobData(jobId).enabled)} set the position for location ${getJobRouteLocationData(jobId, jobRoute, jobRouteLocation).name} on route {ALTCOLOUR}${getJobRouteData(jobId, jobRoute).name} {MAINCOLOUR} of the {jobYellow}${getJobData(jobId).name} {MAINCOLOUR} job`); } // =========================================================================== function setJobRouteDefaultLocationArriveMessageCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); getJobData(jobId).routes[jobRoute].locationArriveMessage = params; getJobData(jobId).routes[jobRoute].needsSaved = true; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} ${getEnabledDisabledFromBool(getJobData(jobId).enabled)} set the location arrival message to {ALTCOLOUR}"${params}"{MAINCOLOUR} for route {ALTCOLOUR}${getJobRouteData(jobId, jobRoute).name} {MAINCOLOUR} of the {jobYellow}${getJobData(jobId).name} {MAINCOLOUR} job`); } // =========================================================================== function setJobRouteDefaultLocationNextMessageCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); getJobData(jobId).routes[jobRoute].locationNextMessage = params; getJobData(jobId).routes[jobRoute].needsSaved = true; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} ${getEnabledDisabledFromBool(getJobData(jobId).enabled)}{MAINCOLOUR} set the location next message to {ALTCOLOUR}"${params}"{MAINCOLOUR} for route {ALTCOLOUR}${getJobRouteData(jobId, jobRoute).name}{MAINCOLOUR} of the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job`); } // =========================================================================== function setJobRoutePayCommand(command, params, client) { if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let jobRoute = getPlayerJobRoute(client); let amount = getParam(params, " ", 1); if (isNaN(amount)) { getLocaleString(client, "MustBeNumber", "amount"); return false; } getJobData(jobId).routes[jobRoute].pay = toInteger(amount); getJobData(jobId).routes[jobRoute].needsSaved = true; messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR} set the pay for route {ALTCOLOUR}${getJobRouteData(jobId, jobRoute).name}{MAINCOLOUR} of the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job to {ALTCOLOUR}${getCurrencyString(amount)} {MAINCOLOUR} `); } // =========================================================================== function toggleJobWhiteListCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getJobFromParams(params) || getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)).jobIndex; getJobData(jobId).whiteListEnabled = !getJobData(jobId).whiteListEnabled; messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR}${getEnabledDisabledFromBool(getJobData(jobId).whiteListEnabled)}{MAINCOLOUR} the whitelist for the {ALTCOLOUR}${getJobData(jobId).name}{MAINCOLOUR} job`); } // =========================================================================== function toggleJobBlackListCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getJobFromParams(params) || getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)).jobIndex; getJobData(jobId).blackListEnabled = !getJobData(jobId).blackListEnabled; messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR} ${getEnabledDisabledFromBool(getJobData(jobId).blackListEnabled)} the blacklist for the {jobYellow}${getJobData(jobId).name} {MAINCOLOUR} job`); } // =========================================================================== function addPlayerToJobBlackListCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let targetClient = getPlayerFromParams(getParam(params, " ", 1)); let jobId = getJobFromParams(getParam(params, " ", 2)) || getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)).jobIndex; if (!targetClient) { messagePlayerError(client, getLocaleString(client, "InvalidPlayer")); return false; } if (!getJobData(jobId)) { messagePlayerError(client, getLocaleString(client, "InvalidJob")); return false; } if (isPlayerOnJobBlackList(targetClient, jobId)) { messagePlayerError(client, `That player is already blacklisted from that job!`); return false; } addPlayerToJobBlackList(targetClient, jobId); messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR} added {ALTCOLOUR}${getCharacterFullName(targetClient)} {MAINCOLOUR} to the blacklist for the {jobYellow}${jobData.name} {MAINCOLOUR} job`); } // =========================================================================== function removePlayerFromJobBlackListCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let targetClient = getPlayerFromParams(getParam(params, " ", 1)); let jobId = getJobFromParams(getParam(params, " ", 2)) || getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)).jobIndex; if (!targetClient) { messagePlayerError(client, getLocaleString(client, "InvalidPlayer")); return false; } if (!getJobData(jobId)) { messagePlayerError(client, getLocaleString(client, "InvalidJob")); return false; } if (!isPlayerOnJobBlackList(targetClient, jobId)) { messagePlayerError(client, `That player is not blacklisted from that job!`); return false; } removePlayerFromJobBlackList(targetClient, jobId); messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR} removed {ALTCOLOUR}${getCharacterFullName(targetClient)} {MAINCOLOUR} from the blacklist for the {jobYellow}${jobData.name} {MAINCOLOUR} job`); } // =========================================================================== function addPlayerToJobWhiteListCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let targetClient = getPlayerFromParams(getParam(params, " ", 1)); let jobId = getJobFromParams(getParam(params, " ", 2)) || getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)).jobIndex; if (!targetClient) { messagePlayerError(client, getLocaleString(client, "InvalidPlayer")); return false; } if (!getJobData(jobId)) { messagePlayerError(client, getLocaleString(client, "InvalidJob")); return false; } if (isPlayerOnJobWhiteList(targetClient, jobId)) { messagePlayerError(client, `That player is already whitelisted from that job!`); return false; } addPlayerToJobWhiteList(targetClient, jobId); messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR}added {ALTCOLOUR}${getCharacterFullName(targetClient)} {MAINCOLOUR} to the whitelist for the {jobYellow}${jobData.name} {MAINCOLOUR} job`); } // =========================================================================== function removePlayerFromJobWhiteListCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let targetClient = getPlayerFromParams(getParam(params, " ", 1)); let jobId = getJobFromParams(getParam(params, " ", 2)) || getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)).jobIndex; if (!targetClient) { messagePlayerError(client, getLocaleString(client, "InvalidPlayer")); return false; } if (!getJobData(jobId)) { messagePlayerError(client, getLocaleString(client, "InvalidJob")); return false; } if (!isPlayerOnJobWhiteList(targetClient, jobId)) { messagePlayerError(client, `That player is not whitelisted from that job!`); return false; } removePlayerFromJobWhiteList(targetClient, jobId); messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR} removed {ALTCOLOUR}${getCharacterFullName(targetClient)} {MAINCOLOUR} from the whitelist for the {jobYellow}${jobData.name} {MAINCOLOUR} job`); } // =========================================================================== function forceAllPlayersToStopWorking() { getClients().forEach(function (client) { if (!client.console) { stopWorking(client); } }); } // =========================================================================== function jobStartRouteCommand(command, params, client) { if (!canPlayerUseJobs(client)) { messagePlayerError(client, "You are not allowed to use jobs."); return false; } if (!isPlayerWorking(client)) { messagePlayerError(client, "You aren't working yet! Use /startwork first."); return false; } if (getJobData(getPlayerJob(client)).routes.length == 0) { messagePlayerError(client, "Your job doesn't have any routes for this location!"); return false; } if (!isPlayerInJobVehicle(client)) { messagePlayerError(client, "You need to be in a vehicle that belongs to your job!"); return false; } if (isPlayerOnJobRoute(client)) { messagePlayerError(client, "You're already on a job route! Finish the route or use /stoproute"); return false; } let forceRoute = -1; if (doesPlayerHaveStaffPermission(client, getStaffFlagValue("ManageJobs"))) { if (!areParamsEmpty(params)) { let tempRoute = getJobRouteFromParams(params, getPlayerJob(client)); if (tempRoute != false) { forceRoute = tempRoute; } } } startJobRoute(client, forceRoute); return true; } // =========================================================================== function jobStopRouteCommand(command, params, client) { if (!canPlayerUseJobs(client)) { messagePlayerError(client, "You are not allowed to use jobs."); return false; } if (!isPlayerWorking(client)) { messagePlayerError(client, "You aren't working yet! Use /startwork first."); return false; } //if(!doesPlayerHaveJobType(client, AGRP_JOB_BUS) && !doesPlayerHaveJobType(client, AGRP_JOB_GARBAGE)) { // messagePlayerError(client, "Your job doesn't use a route!"); // return false; //} if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, "You aren't on a job route!"); return false; } if (!getJobRouteData(getPlayerJob(client), getPlayerJobRoute(client)).enabled) { setAllJobDataIndexes(); getJobRouteData(getPlayerJob(client), getPlayerJobRoute(client)).enabled = true; } stopJobRoute(client, false, false); return true; } // =========================================================================== function isPlayerInJobVehicle(client) { if (getPlayerVehicle(client)) { let vehicle = getPlayerVehicle(client); if (isVehicleOwnedByJob(vehicle, getPlayerCurrentSubAccount(client).job)) { return true; } } return false; } // =========================================================================== function isPlayerWorking(client) { if (!getPlayerCurrentSubAccount(client)) { return false; } return getPlayerCurrentSubAccount(client).isWorking; } // =========================================================================== function startJobRoute(client, forceRoute = -1) { let jobId = getPlayerJob(client); let jobRoute = 0; if (forceRoute == -1) { jobRoute = getRandomJobRouteForLocation(getClosestJobLocationForJob(getPlayerPosition(client), jobId)); } else { jobRoute = forceRoute; } if (jobRoute == -1) { messagePlayerError(client, `There are no routes for this location.`); return false; } logToConsole(LOG_DEBUG, `${getPlayerDisplayForConsole(client)} is starting job route ${getJobRouteData(jobId, jobRoute).name} (${jobRoute}) for the ${getJobData(jobId).name}(${jobId}) job`); getPlayerData(client).jobRoute = jobRoute; getPlayerData(client).jobRouteLocation = 0; getPlayerData(client).jobRouteVehicle = getPlayerVehicle(client); getPlayerVehicle(client).colour1 = getJobRouteData(jobId, jobRoute).vehicleColour1; getPlayerVehicle(client).colour2 = getJobRouteData(jobId, jobRoute).vehicleColour2; messagePlayerNormal(client, replaceJobRouteStringsInMessage(getJobRouteData(jobId, jobRoute).startMessage, jobId, jobRoute)); showSmallGameMessage(client, replaceJobRouteStringsInMessage(removeColoursInMessage(getJobRouteData(jobId, getPlayerJobRoute(client)).locationGotoMessage), jobId, getPlayerJobRoute(client)), getJobData(jobId).colour, 3500); // Don't announce routes that an admin just created if (forceRoute == -1) { messageDiscordEventChannel(`💼 ${getCharacterFullName(client)} started the ${getJobRouteData(jobId, jobRoute).name} route for the ${getJobData(jobId).name} job`); } if (getJobRouteData(jobId, jobRoute).locations.length > 0) { showCurrentJobLocation(client); } else { messagePlayerError(client, `There are no locations for this route.`); } } // =========================================================================== function stopJobRoute(client, successful = false, alertPlayer = true) { let jobId = getPlayerJob(client); let routeId = getPlayerJobRoute(client); if (successful == true) { if (alertPlayer) { messagePlayerAlert(client, replaceJobRouteStringsInMessage(getJobRouteData(jobId, routeId).finishMessage, jobId, routeId)); } finishSuccessfulJobRoute(client); return false; } //if (alertPlayer) { // messagePlayerAlert(client, replaceJobRouteStringsInMessage(getJobRouteData(jobId, routeId).failedMessage, jobId, routeId)); //} messageDiscordEventChannel(`💼 ${getCharacterFullName(client)} failed to finish the ${getJobRouteData(jobId, getPlayerJobRoute(client)).name} route for the ${getJobData(jobId).name} job and didn't earn anything.`); stopReturnToJobVehicleCountdown(client); sendPlayerStopJobRoute(client); respawnVehicle(getPlayerData(client).jobRouteVehicle); getPlayerData(client).jobRouteVehicle = false; getPlayerData(client).jobRoute = -1; getPlayerData(client).jobRouteLocation = -1; } // =========================================================================== function isPlayerOnJobRoute(client) { if (getPlayerData(client).jobRoute != -1) { return true; } return false; } // =========================================================================== function getPlayerJobRouteVehicle(client) { if (!isPlayerOnJobRoute(client)) { return false; } return getPlayerData(client).jobRouteVehicle; } // =========================================================================== function startReturnToJobVehicleCountdown(client) { getPlayerData(client).returnToJobVehicleTick = getGlobalConfig().returnToJobVehicleTime; getPlayerData(client).returnToJobVehicleTimer = setInterval(function () { //logToConsole(LOG_DEBUG, getPlayerData(client).returnToJobVehicleTick); if (getPlayerData(client).returnToJobVehicleTick > 0) { getPlayerData(client).returnToJobVehicleTick = getPlayerData(client).returnToJobVehicleTick - 1; //logToConsole(LOG_WARN, `You have ${getPlayerData(client).returnToJobVehicleTick} seconds to return to your job vehicle!`); showSmallGameMessage(client, `You have ${getPlayerData(client).returnToJobVehicleTick} seconds to return to your job vehicle!`, getColourByName("softRed"), 1500); } else { clearInterval(getPlayerData(client).returnToJobVehicleTimer); getPlayerData(client).returnToJobVehicleTimer = null; getPlayerData(client).returnToJobVehicleTick = 0; stopJobRoute(client, false, true); } }, 1000); } // =========================================================================== function stopReturnToJobVehicleCountdown(client) { if (getPlayerData(client).returnToJobVehicleTimer != null) { clearInterval(getPlayerData(client).returnToJobVehicleTimer); getPlayerData(client).returnToJobVehicleTimer = null; } //getPlayerData(client).returnToJobVehicleTick = 0; } // =========================================================================== function canPlayerUseJob(client, jobId) { if (doesPlayerHaveStaffPermission(client, getStaffFlagValue("ManageJobs"))) { return true; } if (!getJobData(jobId)) { return false; } if (isJobWhiteListed(jobId)) { if (!isPlayerOnJobWhiteList(client, jobId)) { return false; } } if (!isJobBlackListed(jobId)) { if (isPlayerOnJobBlackList(client, jobId)) { return false; } } return true; } // =========================================================================== function deleteJobLocation(jobLocationData) { if (jobLocationData.databaseId > 0) { quickDatabaseQuery(`DELETE FROM job_loc WHERE job_loc_id = ${jobLocationData.databaseId}`); } deleteJobLocationBlip(tempJob, tempLocation); deleteJobLocationPickup(tempJob, tempLocation); getJobData(getJobIdFromDatabaseId(tempJob)).locations.splice(tempLocation, 1); setAllJobDataIndexes(); } // =========================================================================== function freezePlayerJobVehicleForRouteLocation(client) { getVehicleData(getPlayerVehicle(client)).engine = false; setVehicleEngine(getPlayerVehicle(client), getVehicleData(getPlayerVehicle(client)).engine); //setPlayerControlState(client, false); } // =========================================================================== function unFreezePlayerJobVehicleForRouteLocation(client) { getVehicleData(getPlayerVehicle(client)).engine = true; setVehicleEngine(getPlayerVehicle(client), getVehicleData(getPlayerVehicle(client)).engine); //setPlayerControlState(client, true); } // =========================================================================== function getJobIdFromDatabaseId(databaseId) { for (let i in getServerData().jobs) { if (getServerData().jobs[i].databaseId == databaseId) { return i; } } return false; } // =========================================================================== function setAllJobDataIndexes() { for (let i in getServerData().jobs) { getServerData().jobs[i].index = i; for (let j in getServerData().jobs[i].locations) { getServerData().jobs[i].locations[j].index = j; getServerData().jobs[i].locations[j].jobIndex = i; for (let u in getServerData().jobs[i].routes) { if (getServerData().jobs[i].routes[u].locationId == getServerData().jobs[i].locations[j].databaseId) { getServerData().jobs[i].locations[j].routeCache.push(u); } } } for (let k in getServerData().jobs[i].uniforms) { getServerData().jobs[i].uniforms[k].index = k; getServerData().jobs[i].uniforms[k].jobIndex = i; } for (let m in getServerData().jobs[i].equipment) { getServerData().jobs[i].equipment[m].index = m; getServerData().jobs[i].equipment[m].jobIndex = i; for (let n in getServerData().jobs[i].equipment[m].items) { getServerData().jobs[i].equipment[m].items[n].index = n; getServerData().jobs[i].equipment[m].items[n].jobIndex = i; getServerData().jobs[i].equipment[m].items[n].equipmentIndex = m; } } for (let o in getServerData().jobs[i].blackList) { getServerData().jobs[i].blackList[o].index = o; getServerData().jobs[i].blackList[o].jobIndex = i; } for (let v in getServerData().jobs[i].whiteList) { getServerData().jobs[i].blackList[v].index = v; getServerData().jobs[i].blackList[v].jobIndex = i; } for (let t in getServerData().jobs[i].routes) { getServerData().jobs[i].routes[t].index = t; getServerData().jobs[i].routes[t].jobIndex = i; } } } // =========================================================================== function createJobLocation(jobId, position, interior, dimension) { let jobLocationData = new JobLocationData(false); jobLocationData.position = position; jobLocationData.jobId = getJobData(jobId).databaseId; jobLocationData.interior = interior; jobLocationData.dimension = dimension; jobLocationData.enabled = true; jobLocationData.jobIndex = jobId; jobLocationData.needsSaved = true; getServerData().jobs[jobId].locations.push(jobLocationData); let newSlot = getServerData().jobs[jobId].locations.length - 1; getServerData().jobs[jobId].locations[newSlot].index = newSlot; createJobLocationPickup(jobId, newSlot); saveJobLocationToDatabase(jobLocationData); } // =========================================================================== function saveJobToDatabase(jobData) { if (jobData == null) { // Invalid job data return false; } if (jobData.needsSaved == false) { logToConsole(LOG_DEBUG, `[VRR.Job]: Job ${jobData.name} doesn't need saved. Skipping ...`); return false; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saving job ${jobData.name} to database ...`); let dbConnection = connectToDatabase(); if (dbConnection) { let safeName = escapeDatabaseString(dbConnection, jobData.name); let colour = rgbaArrayFromToColour(jobData.colour); let data = [ ["job_name", safeName], ["job_server", jobData.serverId], ["job_enabled", boolToInt(jobData.enabled)], ["job_pickup", jobData.pickupModel], ["job_blip", jobData.blipModel], ["job_type", jobData.type], ["job_colour_r", colour[0]], ["job_colour_g", colour[1]], ["job_colour_b", colour[2]], ["job_walkietalkiefreq", jobData.walkieTalkieFrequency], ["job_wl", jobData.whiteListEnabled], ["job_bl", jobData.blackListEnabled], ["job_who_added", jobData.whoCreated], ["job_when_added", jobData.whenCreated], ]; let dbQuery = null; if (jobData.databaseId == 0) { let queryString = createDatabaseInsertQuery("job_main", data); dbQuery = queryDatabase(dbConnection, queryString); jobData.databaseId = getDatabaseInsertId(dbConnection); } else { let queryString = createDatabaseUpdateQuery("job_main", data, `job_id=${jobData.databaseId}`); dbQuery = queryDatabase(dbConnection, queryString); } jobData.needsSaved = false; freeDatabaseQuery(dbQuery); disconnectFromDatabase(dbConnection); return true; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saved job ${jobData.name} to database!`); return false; } // =========================================================================== function saveJobRankToDatabase(jobRankData) { if (!jobRankData) { // Invalid job route data return false; } if (jobRankData.needsSaved == false) { logToConsole(LOG_DEBUG, `[VRR.Job]: Job route ${jobRankData.name} (DB ID ${jobRankData.databaseId}) doesn't need saved. Skipping ...`); return false; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saving job route ${jobRankData.name} to database ...`); let dbConnection = connectToDatabase(); if (dbConnection) { let safeName = escapeDatabaseString(dbConnection, jobRankData.name); let data = [ ["job_rank_job", jobRankData.jobId], ["job_rank_enabled", boolToInt(jobRankData.enabled)], ["job_rank_name", safeName], ["job_rank_flags", jobRankData.flags], ["job_rank_pay", jobRankData.pay], ["job_rank_level", jobRankData.level], ["job_rank_who_added", jobRankData.whoCreated], ["job_rank_when_added", jobRankData.whenCreated], ]; let dbQuery = null; if (jobRankData.databaseId == 0) { let queryString = createDatabaseInsertQuery("job_rank", data); dbQuery = queryDatabase(dbConnection, queryString); jobRankData.databaseId = getDatabaseInsertId(dbConnection); } else { let queryString = createDatabaseUpdateQuery("job_rank", data, `job_rank_id=${jobRankData.databaseId}`); dbQuery = queryDatabase(dbConnection, queryString); } jobRankData.needsSaved = false; freeDatabaseQuery(dbQuery); disconnectFromDatabase(dbConnection); return true; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saved job rank ${jobRankData.name} to database!`); return false; } // =========================================================================== function saveJobRouteToDatabase(jobRouteData) { if (!jobRouteData) { // Invalid job route data return false; } if (jobRouteData.needsSaved == false) { logToConsole(LOG_DEBUG, `[VRR.Job]: Job route ${jobRouteData.name} (DB ID ${jobRouteData.databaseId}) doesn't need saved. Skipping ...`); return false; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saving job route ${jobRouteData.name} to database ...`); let dbConnection = connectToDatabase(); if (dbConnection) { let safeName = escapeDatabaseString(dbConnection, jobRouteData.name); let safeStartMessage = escapeDatabaseString(dbConnection, jobRouteData.startMessage); let safeFinishMessage = escapeDatabaseString(dbConnection, jobRouteData.finishMessage); let safeLocationArriveMessage = escapeDatabaseString(dbConnection, jobRouteData.locationArriveMessage); let safeLocationNextMessage = escapeDatabaseString(dbConnection, jobRouteData.locationNextMessage); let data = [ ["job_route_job", jobRouteData.jobId], ["job_route_job_loc", jobRouteData.locationId], ["job_route_enabled", boolToInt(jobRouteData.enabled)], ["job_route_name", safeName], ["job_route_veh_colour1", jobRouteData.vehicleColour1], ["job_route_veh_colour2", jobRouteData.vehicleColour2], ["job_route_start_msg", safeStartMessage], ["job_route_finish_msg", safeFinishMessage], ["job_route_loc_arrive_msg", safeLocationArriveMessage], ["job_route_loc_goto_msg", safeLocationNextMessage], ["job_route_pay", jobRouteData.pay], ["job_route_detail", jobRouteData.detail], ["job_route_who_added", jobRouteData.whoCreated], ["job_route_when_added", jobRouteData.whenCreated], ]; let dbQuery = null; if (jobRouteData.databaseId == 0) { let queryString = createDatabaseInsertQuery("job_route", data); dbQuery = queryDatabase(dbConnection, queryString); jobRouteData.databaseId = getDatabaseInsertId(dbConnection); } else { let queryString = createDatabaseUpdateQuery("job_route", data, `job_route_id=${jobRouteData.databaseId}`); dbQuery = queryDatabase(dbConnection, queryString); } jobRouteData.needsSaved = false; freeDatabaseQuery(dbQuery); disconnectFromDatabase(dbConnection); return true; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saved job route ${jobRouteData.name} to database!`); return false; } // =========================================================================== function saveJobRouteLocationToDatabase(jobRouteLocationData) { if (!jobRouteLocationData) { // Invalid job route position data return false; } if (jobRouteLocationData.needsSaved == false) { logToConsole(LOG_DEBUG, `[VRR.Job]: Job route location ${jobRouteLocationData.name} (DB ID ${jobRouteLocationData.databaseId}) doesn't need saved. Skipping ...`); return false; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saving job route location ${jobRouteLocationData.name} to database ...`); let dbConnection = connectToDatabase(); if (dbConnection) { let safeName = escapeDatabaseString(dbConnection, jobRouteLocationData.name); let data = [ ["job_route_loc_route", jobRouteLocationData.routeId], ["job_route_loc_enabled", boolToInt(jobRouteLocationData.enabled)], ["job_route_loc_name", safeName], ["job_route_loc_x", jobRouteLocationData.position.x], ["job_route_loc_y", jobRouteLocationData.position.y], ["job_route_loc_z", jobRouteLocationData.position.z], ["job_route_loc_pay", jobRouteLocationData.pay], ["job_route_loc_delay", jobRouteLocationData.stopDelay], ["job_route_loc_who_added", jobRouteLocationData.whoCreated], ["job_route_loc_when_added", jobRouteLocationData.whenCreated], ]; let dbQuery = null; if (jobRouteLocationData.databaseId == 0) { let queryString = createDatabaseInsertQuery("job_route_loc", data); dbQuery = queryDatabase(dbConnection, queryString); jobRouteLocationData.databaseId = getDatabaseInsertId(dbConnection); } else { let queryString = createDatabaseUpdateQuery("job_route_loc", data, `job_route_loc_id=${jobRouteLocationData.databaseId}`); dbQuery = queryDatabase(dbConnection, queryString); } jobRouteLocationData.needsSaved = false; freeDatabaseQuery(dbQuery); disconnectFromDatabase(dbConnection); return true; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saved job route location ${jobRoutePositionData.name} (${jobRouteLocationData.databaseId}) to database!`); return false; } // =========================================================================== function saveJobLocationToDatabase(jobLocationData) { if (jobLocationData == null) { // Invalid job location data return false; } if (!jobLocationData.needsSaved) { logToConsole(LOG_DEBUG, `[VRR.Job]: Job location ${jobLocationData.name} (${jobLocationData.databaseId}) doesn't need saved. Skipping ...`); return false; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saving job location ${jobLocationData.databaseId} to database ...`); let dbConnection = connectToDatabase(); if (dbConnection) { let data = [ ["job_loc_job", jobLocationData.jobId], ["job_loc_enabled", boolToInt(jobLocationData.enabled)], ["job_loc_pos_x", jobLocationData.position.x], ["job_loc_pos_y", jobLocationData.position.y], ["job_loc_pos_z", jobLocationData.position.z], ["job_loc_int", jobLocationData.interior], ["job_loc_vw", jobLocationData.dimension], ["job_loc_who_added", jobLocationData.whoCreated], ["job_loc_when_added", jobLocationData.whenCreated], ]; let dbQuery = null; if (jobLocationData.databaseId == 0) { let queryString = createDatabaseInsertQuery("job_loc", data); dbQuery = queryDatabase(dbConnection, queryString); jobLocationData.databaseId = getDatabaseInsertId(dbConnection); } else { let queryString = createDatabaseUpdateQuery("job_loc", data, `job_loc_id=${jobLocationData.databaseId}`); dbQuery = queryDatabase(dbConnection, queryString); } jobLocationData.needsSaved = false; freeDatabaseQuery(dbQuery); disconnectFromDatabase(dbConnection); return true; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saved job location ${jobLocationData.databaseId} to database`); return false; } // =========================================================================== function saveJobEquipmentToDatabase(jobEquipmentData) { if (jobEquipmentData == null) { // Invalid job equipment data return false; } if (!jobEquipmentData.needsSaved) { logToConsole(LOG_DEBUG, `[VRR.Job]: Job equipment ${jobEquipmentData.name} (${jobEquipmentData.databaseId}) doesn't need saved. Skipping ...`); return false; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saving job equipment ${jobEquipmentData.databaseId} to database ...`); let dbConnection = connectToDatabase(); if (dbConnection) { let safeName = escapeDatabaseString(dbConnection, jobEquipmentData.name); let data = [ ["job_equip_job", jobEquipmentData.job], ["job_equip_enabled", boolToInt(jobEquipmentData.enabled)], ["job_equip_minrank", jobLocationData.requiredRank], ["job_equip_name", safeName], ["job_equip_who_added", jobEquipmentData.whoCreated], ["job_equip_when_added", jobEquipmentData.whenCreated], ]; let dbQuery = null; if (tempJobRouteData.databaseId == 0) { let queryString = createDatabaseInsertQuery("job_equip", data); dbQuery = queryDatabase(dbConnection, queryString); jobEquipmentData.databaseId = getDatabaseInsertId(dbConnection); } else { let queryString = createDatabaseUpdateQuery("job_equip", data, `job_equip_id=${jobEquipmentData.databaseId}`); dbQuery = queryDatabase(dbConnection, queryString); } jobEquipmentData.needsSaved = false; freeDatabaseQuery(dbQuery); disconnectFromDatabase(dbConnection); return true; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saved job equipment ${jobEquipmentData.databaseId} to database`); return false; } // =========================================================================== function saveJobEquipmentItemToDatabase(jobEquipmentItemData) { if (jobEquipmentItemData == null) { // Invalid job equipment weapon data return false; } if (!jobEquipmentItemData.needsSaved) { logToConsole(LOG_DEBUG, `[VRR.Job]: Job equipment item ${jobEquipmentItemData.databaseId} doesn't need saved. Skipping ...`); return false; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saving job equipment weapon ${jobEquipmentItemData.databaseId} to database ...`); let dbConnection = connectToDatabase(); if (dbConnection) { let data = [ ["job_equip_item_equip", jobEquipmentItemData.equipmentId], ["job_equip_item_enabled", boolToInt(jobEquipmentItemData.enabled)], ["job_equip_item_type", jobEquipmentItemData.itemType], ["job_equip_item_value", jobEquipmentItemData.value], ["job_equip_item_who_added", jobEquipmentItemData.whoCreated], ["job_equip_item_when_added", jobEquipmentItemData.whenCreated], ]; let dbQuery = null; if (tempJobRouteData.databaseId == 0) { let queryString = createDatabaseInsertQuery("job_equip_item", data); dbQuery = queryDatabase(dbConnection, queryString); jobEquipmentItemData.databaseId = getDatabaseInsertId(dbConnection); } else { let queryString = createDatabaseUpdateQuery("job_equip_item", data, `job_equip_id=${jobEquipmentItemData.databaseId}`); dbQuery = queryDatabase(dbConnection, queryString); } jobEquipmentItemData.needsSaved = false; freeDatabaseQuery(dbQuery); disconnectFromDatabase(dbConnection); return true; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saved job equipment weapon ${jobEquipmentItemData.databaseId} to database`); return false; } // =========================================================================== function saveJobUniformToDatabase(jobUniformData) { if (jobUniformData == null) { // Invalid job uniform data return false; } if (!jobUniformData.needSaved) { logToConsole(LOG_DEBUG, `[VRR.Job]: Job uniform ${jobUniformData.databaseId} doesn't need saved. Skipping ...`); return false; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saving job uniform ${jobUniformData.databaseId} to database ...`); let dbConnection = connectToDatabase(); if (dbConnection) { let safeName = escapeDatabaseString(dbConnection, jobUniformData.name); let data = [ ["job_uniform_job", jobUniformData.jobId], ["job_uniform_enabled", boolToInt(jobUniformData.enabled)], ["job_uniform_minrank", jobUniformData.requiredRank], ["job_uniform_name", safeName], ["job_uniform_model", jobUniformData.skin], ["job_uniform_who_added", jobUniformData.whoCreated], ["job_uniform_when_added", jobUniformData.whenCreated], ]; let dbQuery = null; if (tempJobRouteData.databaseId == 0) { let queryString = createDatabaseInsertQuery("job_uniform", data); dbQuery = queryDatabase(dbConnection, queryString); jobUniformData.databaseId = getDatabaseInsertId(dbConnection); } else { let queryString = createDatabaseUpdateQuery("job_uniform", data, `job_uniform_id=${jobUniformData.databaseId}`); dbQuery = queryDatabase(dbConnection, queryString); } jobUniformData.needsSaved = false; freeDatabaseQuery(dbQuery); disconnectFromDatabase(dbConnection); return true; } logToConsole(LOG_DEBUG, `[VRR.Job]: Saved job uniform ${jobUniformData.databaseId} to database`); return false; } // =========================================================================== function saveAllJobsToDatabase() { for (let i in getServerData().jobs) { saveJobToDatabase(getServerData().jobs[i]); for (let j in getServerData().jobs[i].locations) { saveJobLocationToDatabase(getServerData().jobs[i].locations[j]); } for (let k in getServerData().jobs[i].uniforms) { saveJobUniformToDatabase(getServerData().jobs[i].uniforms[k]); } for (let m in getServerData().jobs[i].equipment) { saveJobEquipmentToDatabase(getServerData().jobs[i].equipment[m]); for (let n in getServerData().jobs[i].equipment[m].items) { saveJobEquipmentItemToDatabase(getServerData().jobs[i].equipment[m].items[n]); } } for (let p in getServerData().jobs[i].routes) { saveJobRouteToDatabase(getServerData().jobs[i].routes[p]); for (let q in getServerData().jobs[i].routes[p].locations) { saveJobRouteLocationToDatabase(getServerData().jobs[i].routes[p].locations[q]); } } for (let r in getServerData().jobs[i].ranks) { saveJobRankToDatabase(getServerData().jobs[i].ranks[r]); } } } // =========================================================================== function deleteJobLocationBlip(jobId, locationId) { if (getJobData(jobId).locations[locationId].blip != null) { deleteGameElement(getJobData(jobId).locations[locationId].blip); getJobData(jobId).locations[locationId].blip = null; } } // =========================================================================== function deleteJobLocationPickup(jobId, locationId) { if (getServerData().jobs[jobId].locations[locationId].pickup != null) { deleteGameElement(getJobData(jobId).locations[locationId].pickup); getServerData().jobs[jobId].locations[locationId].pickup = null; } } // =========================================================================== function createJobLocationPickup(jobId, locationId) { if (!getServerConfig().createJobPickups) { return false; } if (!isGameFeatureSupported("pickup")) { return false; } let tempJobData = getJobData(jobId); if (tempJobData.pickupModel != -1) { let pickupModelId = getGameConfig().pickupModels[getGame()].Job; if (tempJobData.pickupModel != 0) { pickupModelId = tempJobData.pickupModel; } logToConsole(LOG_VERBOSE, `[VRR.Job]: Creating pickup for location ${locationId} of the ${tempJobData.name} job`); if (areServerElementsSupported()) { let pickup = createGamePickup(pickupModelId, tempJobData.locations[locationId].position, getGameConfig().pickupTypes[getGame()].job); if (pickup != false) { tempJobData.locations[locationId].pickup = pickup; setElementDimension(pickup, tempJobData.locations[locationId].dimension); setElementOnAllDimensions(pickup, false); setEntityData(pickup, "agrp.owner.type", AGRP_PICKUP_JOB, false); setEntityData(pickup, "agrp.owner.id", locationId, false); setEntityData(pickup, "agrp.label.type", AGRP_LABEL_JOB, true); setEntityData(pickup, "agrp.label.name", tempJobData.name, true); setEntityData(pickup, "agrp.label.jobType", tempJobData.databaseId, true); addToWorld(pickup); } } else { // sendJobToPlayer(null, jobId, tempJobData.name, tempJobData.locations[locationId].position, pickupModel); } } } // =========================================================================== function createJobLocationBlip(jobId, locationId) { if (!getServerConfig().createJobBlips) { return false; } if (!isGameFeatureSupported("blip")) { return false; } let tempJobData = getJobData(jobId); if (getJobData(jobId).blipModel == -1) { return false; } let blipModelId = getGameConfig().blipSprites[getGame()].Job; if (getJobData(jobId).blipModel != 0) { blipModelId = getJobData(jobId).blipModel; } if (areServerElementsSupported()) { let blip = createGameBlip(tempJobData.locations[locationId].position, blipModelId, 2, getColourByName("yellow")); if (blip != false) { tempJobData.locations[locationId].blip = blip; if (getGlobalConfig().jobBlipStreamInDistance == -1 || getGlobalConfig().jobBlipStreamOutDistance == -1) { blip.netFlags.distanceStreaming = false; } else { setElementStreamInDistance(blip, getGlobalConfig().jobBlipStreamInDistance); setElementStreamOutDistance(blip, getGlobalConfig().jobBlipStreamOutDistance); } setElementOnAllDimensions(blip, false); setElementDimension(blip, tempJobData.locations[locationId].dimension); let clients = getClients(); for (let i in clients) { updateJobBlipsForPlayer(clients[i]); } } } else { sendJobToPlayer(null, jobId, tempJobData.name, tempJobData.locations[locationId].position, blipModelId); } } // =========================================================================== function getPlayerJob(client) { return getPlayerCurrentSubAccount(client).jobIndex; } // =========================================================================== function getPlayerJobRank(client) { return getPlayerCurrentSubAccount(client).jobRankIndex; } // =========================================================================== function doesPlayerHaveAnyJob(client) { return (getPlayerJob(client) != -1); } // =========================================================================== function canPlayerUseJobs(client) { if (hasBitFlag(getPlayerData(client).accountData.flags.moderation, getServerBitFlags().moderationFlags.JobBanned)) { return false; } return true; } // =========================================================================== function getJobIndexFromDatabaseId(databaseId) { for (let i in getServerData().jobs) { if (getServerData().jobs[i].databaseId == databaseId) { return i; } } return false; } // =========================================================================== function getJobRankIndexFromDatabaseId(jobIndex, databaseId) { if (databaseId <= 0) { return -1; } for (let i in getServerData().jobs[jobIndex].ranks) { if (getServerData().jobs[jobIndex].ranks[i].databaseId == databaseId) { return i; } } return -1; } // =========================================================================== function isJobWhiteListed(jobId) { return getJobData(jobId).whiteListEnabled; } // =========================================================================== function isPlayerOnJobWhiteList(client, jobId) { for (let i in getJobData(jobId).whiteList) { if (getJobData(jobId).whiteList[i].subAccount == getPlayerCurrentSubAccount(client).databaseId) { return true; } } return false; } // =========================================================================== function isJobBlackListed(jobId) { return getJobData(jobId).blackListEnabled; } // =========================================================================== function isPlayerOnJobBlackList(client, jobId) { for (let i in getJobData(jobId).blackList) { if (getJobData(jobId).blackList[i].subAccount == getPlayerCurrentSubAccount(client).databaseId) { return true; } } return false; } // =========================================================================== function playerArrivedAtJobRouteLocation(client) { let jobId = getPlayerJob(client); let jobRouteId = getPlayerJobRoute(client); let jobRouteLocationId = getPlayerJobRouteLocation(client); let jobData = getJobData(jobId); let jobRouteData = getJobRouteData(jobId, jobRouteId); if (!isPlayerOnJobRoute(client)) { return false; } if (isLastLocationOnJobRoute(jobId, jobRouteId, jobRouteLocationId)) { finishSuccessfulJobRoute(client); return false; } //hideElementForPlayer(getJobRouteLocationData(jobId, jobRouteId, jobRouteLocationId).marker, client); showSmallGameMessage(client, replaceJobRouteStringsInMessage(removeColoursInMessage(jobRouteData.locationArriveMessage), jobId, jobRouteId), jobData.colour, 3500); if (getJobRouteLocationData(jobId, jobRouteId, jobRouteLocationId).stopDelay > 0) { freezePlayerJobVehicleForRouteLocation(client); getPlayerData(client).jobRouteLocation = getNextLocationOnJobRoute(jobId, jobRouteId, jobRouteLocationId); setTimeout(function () { showCurrentJobLocation(client); showSmallGameMessage(client, replaceJobRouteStringsInMessage(removeColoursInMessage(jobRouteData.locationNextMessage), jobId, jobRouteId), jobData.colour, 3500); unFreezePlayerJobVehicleForRouteLocation(client); }, getJobRouteLocationData(jobId, jobRouteId, jobRouteLocationId).stopDelay); } else { getPlayerData(client).jobRouteLocation = getNextLocationOnJobRoute(jobId, jobRouteId, jobRouteLocationId); showCurrentJobLocation(client); showSmallGameMessage(client, replaceJobRouteStringsInMessage(removeColoursInMessage(jobRouteData.locationNextMessage), jobId, jobRouteId), jobData.colour, 3500); } } // =========================================================================== function deleteJobItems(client) { for (let i in getPlayerData(client).jobEquipmentCache) { deleteItem(getPlayerData(client).jobEquipmentCache[i]); } cachePlayerHotBarItems(client); updatePlayerHotBar(client); } // =========================================================================== function getJobRankName(jobId, rankId) { return jobRankNames[jobId][rankId]; } // =========================================================================== function respawnPlayerLastJobVehicle(client) { if (getPlayerCurrentSubAccount(client).lastJobVehicle == null) { return false; } respawnVehicle(getPlayerCurrentSubAccount(client).lastJobVehicle); } // =========================================================================== function resetAllJobBlips() { deleteAllJobBlips(); createAllJobBlips(); } // =========================================================================== function resetAllJobPickups() { deleteAllJobPickups(); createAllJobPickups(); } // =========================================================================== function deleteAllJobBlips() { for (let i in getServerData().jobs) { deleteJobBlips(i); } } // =========================================================================== function deleteAllJobPickups() { for (let i in getServerData().jobs) { deleteJobPickups(i); } } // =========================================================================== function deleteJobBlips(jobId) { for (let j in getServerData().jobs[jobId].locations) { deleteJobLocationBlip(jobId, j); } } // =========================================================================== function deleteJobPickups(jobId) { for (let j in getServerData().jobs[jobId].locations) { deleteJobLocationPickup(jobId, j); } } // =========================================================================== function createJobRouteCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); let closestJobLocation = getClosestJobLocation(getPlayerPosition(client), getPlayerDimension(client)); if (!getJobData(jobId)) { messagePlayerError(client, `You need to take the job that you want to make a route for.`); return false; } if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "AlreadyOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } let routeId = createJobRoute(params, closestJobLocation, getPlayerData(client).accountData.databaseId); messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} created route {ALTCOLOUR}${params}{MAINCOLOUR} for job {jobYellow}${getJobData(jobId).name}`); startJobRoute(client, routeId); return true; } // =========================================================================== function createJobRouteLocationCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let jobId = getPlayerJob(client); if (!getJobData(jobId)) { messagePlayerError(client, `You need to take the job that you want to make a route location for.`); return false; } if (!isPlayerWorking(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeWorking", "{ALTCOLOUR}/startwork{MAINCOLOUR}")); return false; } if (!isPlayerOnJobRoute(client)) { messagePlayerError(client, getLocaleString(client, "NeedToBeOnJobRoute", "{ALTCOLOUR}/startroute{MAINCOLOUR}")); return false; } let routeId = getPlayerData(client).jobRoute; let jobRouteData = getJobRouteData(jobId, routeId); let routeLocationName = params; createJobRouteLocation( routeLocationName, getPlayerPosition(client), jobRouteData, getPlayerData(client).accountData.databaseId, getPlayerData(client).jobRouteEditNextLocationDelay, getPlayerData(client).jobRouteEditNextLocationArriveMessage, getPlayerData(client).jobRouteEditNextLocationDepartMessage, getPlayerData(client).jobRouteEditNextLocationType ); getPlayerData(client).jobRouteEditNextLocationDelay = 0; getPlayerData(client).jobRouteEditNextLocationArriveMessage = jobRouteData.locationArriveMessage; getPlayerData(client).jobRouteEditNextLocationGotoMessage = jobRouteData.locationGotoMessage; getPlayerData(client).jobRouteEditNextLocationType = jobRouteData.locationType; messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} created location {ALTCOLOUR}${routeLocationName}{MAINCOLOUR} for route {ALTCOLOUR}${jobRouteData.name}{MAINCOLOUR} for job {jobYellow}${getJobData(jobId).name}`); return true; } // =========================================================================== function createJobUniformCommand(command, params, client) { if (areParamsEmpty(params)) { messagePlayerSyntax(client, getCommandSyntaxText(command)); return false; } let splitParams = params.spli(" "); let jobId = getJobFromParams(getParam(params, " ", 1)); let skinIndex = getSkinModelIndexFromParams(splitParams.slice(1).join(" "), getGame()); if (!getJobData(jobId)) { messagePlayerError(client, getLocaleString(client, "InvalidJob")); return false; } if (!skinIndex) { messagePlayerError(client, getLocaleString(client, "InvalidSkin")); return false; } createJobUniform(jobId, skinIndex); messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} created uniform with skin {ALTCOLOUR}${getGameConfig().skins[skinIndex][1]} (}${getGameConfig().skins[skinIndex][0]}){MAINCOLOUR} for job {jobYellow}${getJobData(jobId).name}`); return true; } // =========================================================================== function createJobRoute(routeName, closestJobLocation, whoCreated = defaultNoAccountId) { let tempJobRouteData = new JobRouteData(false); tempJobRouteData.name = routeName; tempJobRouteData.jobId = closestJobLocation.jobId; tempJobRouteData.locationId = closestJobLocation.databaseId; tempJobRouteData.enabled = false; tempJobRouteData.needsSaved = true; tempJobRouteData.vehicleColour1 = 1; tempJobRouteData.vehicleColour2 = 1; tempJobRouteData.pay = 500; tempJobRouteData.jobIndex = closestJobLocation.jobIndex; tempJobRouteData.startMessage = `You are now on route {ALTCOLOUR}{JOBROUTENAME}{MAINCOLOUR} for the {jobYellow}{JOBNAME}{MAINCOLOUR} job!`; tempJobRouteData.finishMessage = `You have finished the {ALTCOLOUR}{JOBROUTENAME}{MAINCOLOUR} route and {ALTCOLOUR}{JOBROUTEPAY}{MAINCOLOUR} has been added to your next paycheck!`; tempJobRouteData.locationArriveMessage = `You arrived at a stop.`; tempJobRouteData.locationGotoMessage = `Drive to the next stop.`; tempJobRouteData.whoCreated = whoCreated; tempJobRouteData.whenCreated = getCurrentUnixTimestamp(); let routeId = getJobData(closestJobLocation.jobIndex).routes.push(tempJobRouteData); saveJobRouteToDatabase(tempJobRouteData); setAllJobDataIndexes(); return routeId - 1; } // =========================================================================== function createJobRouteLocation(routeLocationName, position, jobRouteData, whoCreated = defaultNoAccountId, delay = 0, arriveMessage = "", gotoMessage = "", type = AGRP_JOB_ROUTE_LOCATION_TYPE_NONE) { let tempJobRouteLocationData = new JobRouteLocationData(false); tempJobRouteLocationData.name = routeLocationName; tempJobRouteLocationData.routeId = jobRouteData.databaseId; tempJobRouteLocationData.enabled = true; tempJobRouteLocationData.needsSaved = true; tempJobRouteLocationData.position = position; tempJobRouteLocationData.routeIndex = jobRouteData.index; tempJobRouteLocationData.stopDelay = delay; tempJobRouteLocationData.arriveMessage = arriveMessage; tempJobRouteLocationData.gotoMessage = gotoMessage; tempJobRouteLocationData.type = type; tempJobRouteLocationData.whoCreated = whoCreated; tempJobRouteLocationData.whenCreated = getCurrentUnixTimestamp(); getJobData(jobRouteData.jobIndex).routes[jobRouteData.index].locations.push(tempJobRouteLocationData); //saveJobRouteLocationToDatabase(tempJobRouteLocationData); //setAllJobDataIndexes(); } // =========================================================================== function createJobUniform(jobId, skinIndex) { let tempJobUniformData = new JobUniformData(false); tempJobUniformData.skin = skinIndex; tempJobUniformData.jobIndex = jobId; tempJobUniformData.job = getJobData(jobId); tempJobUniformData.needsSaved = true; getJobData(jobId).uniforms.push(tempJobUniformData); setAllJobDataIndexes(); } // =========================================================================== function deleteJobRouteLocationCommand(command, params, client) { let closestJobRouteLocation = getClosestJobRouteLocation(getPlayerPosition(client)); messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} deleted route location {ALTCOLOUR}${closestJobRouteLocation.index} (DB ID ${closestJobRouteLocation.databaseId}){MAINCOLOUR} for the {ALTCOLOUR}${closestJobRouteLocation.name}{jobYellow} route of the {jobYellow}${getJobData(closestJobLocation.jobIndex).name}{MAINCOLOUR} job`); if (closestJobRouteLocation.databaseId > 0) { quickDatabaseQuery(`DELETE FROM job_route_loc WHERE job_route_loc_id = ${closestJobRouteLocation.databaseId}`); } let tempIndex = closestJobRouteLocation.index; let tempJobRoute = closestJobRouteLocation.routeIndex; getJobData(getJobIdFromDatabaseId(tempJob)).routes[tempJobRoute].locations.splice(tempIndex, 1); setAllJobDataIndexes(); collectAllGarbage(); } // =========================================================================== function deleteJobRouteCommand(command, params, client) { let jobId = getPlayerJob(client); let jobRoute = getPlayerData(client).jobRoute; if (!areParamsEmpty(client)) { jobRoute = getJobRouteFromParams(params, jobId); } let jobRouteData = getServerData().jobs[jobId].routes[jobRoute]; let clients = getClients(); for (let i in clients) { if (isPlayerWorking(clients[i])) { if (isPlayerOnJobRoute(clients[i])) { if (getPlayerJob(clients[i]) == jobId && getPlayerData(clients[i]).jobRoute == jobRoute) { stopJobRoute(clients[i], true, false); messagePlayerAlert(clients[i], getLocaleString(client, "CurrentJobRouteDeleted")); } } } } messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} deleted route {ALTCOLOUR}${jobRouteData.name} (DB ID ${jobRouteData.databaseId}){MAINCOLOUR} for the {jobYellow}${getJobData(jobId).name}{MAINCOLOUR} job`); if (jobRouteData.databaseId > 0) { quickDatabaseQuery(`DELETE FROM job_route WHERE job_route_id = ${jobRouteData.databaseId}`); quickDatabaseQuery(`DELETE FROM job_route_loc WHERE job_route_loc_route = ${jobRouteData.databaseId}`); } clearArray(getServerData().jobs[jobId].routes[jobRoute].locations); getServerData().jobs[jobId].routes.splice(jobRoute, 1); setAllJobDataIndexes(); collectAllGarbage(); } // =========================================================================== function deleteJobUniformCommand(command, params, client) { let jobId = getJobFromParams(getParam(params, " ", 1)); let uniformIndex = getParam(params, " ", 1); if (!getJobData(jobId)) { messagePlayerError(client, getLocaleString(client, "InvalidJob")); return false; } if (isNaN(uniformIndex)) { messagePlayerError(client, getLocaleString(client, "MustBeNumber", "uniform ID")); return false; } if (typeof getJobData(jobId).uniforms[uniformIndex] == "undefined") { messagePlayerError(client, getLocaleString(client, "InvalidJobUniform")); return false; } quickDatabaseQuery(`DELETE FROM job_uniform WHERE job_uniform_id = ${getJobData(jobId).uniforms[uniformIndex].databaseId}`); getJobData(jobId).uniforms.splice(uniformIndex, 1); setAllJobDataIndexes(); collectAllGarbage(); } // =========================================================================== function getJobFromParams(params) { if (isNaN(params)) { for (let i in getServerData().jobs) { if (toLowerCase(getServerData().jobs[i].name).indexOf(toLowerCase(params)) != -1) { return i; } } } else { if (typeof getServerData().jobs[params] != "undefined") { return params; } } return false; } // =========================================================================== /** * @param {Vector3} position - The position to get the closest job location for * @param {Number} dimension - The dimension to get the closest job location for * @return {JobLocationData} The job location's data (class instance) */ function getClosestJobLocation(position, dimension = 0) { let closestJobLocation = false; let jobs = getServerData().jobs; for (let i in jobs) { let locations = jobs[i].locations; for (let j in locations) { if (locations[j].dimension != dimension) { let businessId = getClosestBusinessExit(locations[j].position, locations[j].dimension); if (getBusinessData(businessId) != false) { if (!closestJobLocation || getBusinessData(businessId).entrancePosition.distance(position) < closestJobLocation.position.distance(position)) { closestJobLocation = locations[j]; } } } if (!closestJobLocation || locations[j].position.distance(position) < closestJobLocation.position.distance(position)) { closestJobLocation = locations[j]; } } } return closestJobLocation; } // =========================================================================== /** * @param {Vector3} position - The position to get the closest job route location for * @return {JobRouteLocationData} The job route location's data (class instance) */ function getClosestJobRouteLocation(position) { let closestJobRouteLocation = false; for (let i in getServerData().jobs) { for (let j in getServerData().jobs[i].routes) { for (let k in getServerData().jobs[i].routes[j].locations) { if (!closestJobRouteLocation || getServerData().jobs[i].routes[j].locations[k].position.distance(position) < closestJobRouteLocation.position.distance(position)) { closestJobRouteLocation = getServerData().jobs[i].routes[j].locations[k]; } } } } return closestJobRouteLocation; } // =========================================================================== function getJobPointsInRange(position, distance) { return getServerData().jobs[getGame()].filter(x => x.position.distance(position) <= distance); } // =========================================================================== function respawnJobVehicle(client) { respawnVehicle(getPlayerJobVehicle(client)); } // =========================================================================== function getPlayerJobVehicle(client) { return getPlayerData(client).lastJobVehicle; } // =========================================================================== function getRandomJobRouteForLocation(closestJobLocation) { if (closestJobLocation.routeCache.length > 0) { let randomRoute = getRandom(0, closestJobLocation.routeCache.length - 1); let routeId = closestJobLocation.routeCache[randomRoute]; if (!getJobRouteData(closestJobLocation.jobIndex, routeId).enabled) { return getRandomJobRouteForLocation(closestJobLocation); } return getJobRouteData(closestJobLocation.jobIndex, routeId).index; } return -1; } // =========================================================================== /** * @param {number} jobIndex - The data index of the job * @param {number} uniformIndex - The data index of the job route * @return {JobUniformData} The jobroutes's data (class instance) */ function getJobUniformData(jobIndex, uniformIndex) { return getServerData().jobs[jobIndex].uniforms[uniformIndex]; } // =========================================================================== /** * @param {number} jobIndex - The data index of the job * @param {number} equipmentIndex - The data index of the job equipment loadout * @return {JobEquipmentData} The job equipment loadout's data (class instance) */ function getJobEquipmentData(jobIndex, equipmentIndex) { return getServerData().jobs[jobIndex].equipment[equipmentIndex]; } // =========================================================================== /** * @param {number} jobIndex - The data index of the job * @param {number} equipmentIndex - The data index of the job equipment loadout * @param {number} equipmentItemIndex - The data index of the job equipment item * @return {JobEquipmentItemData} The job equipment loadout's data (class instance) */ function getJobEquipmentItemData(jobIndex, equipmentIndex, equipmentItemIndex) { return getJobEquipmentData(jobIndex, equipmentIndex).items[equipmentItemIndex]; } // =========================================================================== /** * @param {number} jobIndex - The data index of the job * @param {number} rankIndex - The data index of the job rank * @return {JobRouteData} The job rank's data (class instance) */ function getJobRankData(jobIndex, rankIndex) { return getServerData().jobs[jobIndex].ranks[rankIndex]; } // =========================================================================== /** * @param {number} jobIndex - The data index of the job * @param {number} routeIndex - The data index of the job route * @return {JobRouteData} The job routes's data (class instance) */ function getJobRouteData(jobIndex, routeIndex) { return getServerData().jobs[jobIndex].routes[routeIndex]; } // =========================================================================== /** * @param {number} jobIndex - The data index of the job * @param {number} routeIndex - The data index of the job route * @param {number} routeLocationIndex - The data index of the job route location * @return {JobRouteLocationData} The job route locations's data (class instance) */ function getJobRouteLocationData(jobIndex, routeIndex, routeLocationIndex) { return getJobRouteData(jobIndex, routeIndex).locations[routeLocationIndex]; } // =========================================================================== function getClosestJobLocationForJob(position, jobId) { let closestJobLocation = false; for (let i in getServerData().jobs[jobId].locations) { if (!closestJobLocation || getServerData().jobs[jobId].locations[i].position.distance(position) < closestJobLocation.position.distance(position)) { closestJobLocation = getServerData().jobs[jobId].locations[i]; } } return closestJobLocation; } // =========================================================================== function getPlayerJobRoute(client) { return getPlayerData(client).jobRoute; } // =========================================================================== function getPlayerJobRouteLocation(client) { return getPlayerData(client).jobRouteLocation; } // =========================================================================== function showCurrentJobLocation(client) { sendJobRouteLocationToPlayer(client, getJobRouteLocationData(getPlayerJob(client), getPlayerJobRoute(client), getPlayerJobRouteLocation(client)).position, getJobData(getPlayerJob(client)).colour); //showElementForPlayer(getJobRouteLocationData(getPlayerJob(client), getPlayerJobRoute(client), getPlayerJobRouteLocation(client)).marker, client); } // =========================================================================== function finishSuccessfulJobRoute(client) { let jobId = getPlayerJob(client); let jobRouteId = getPlayerJobRoute(client); let jobRouteData = getJobRouteData(jobId, jobRouteId); let payout = toInteger(applyServerInflationMultiplier(jobRouteData.pay)); getPlayerData(client).payDayAmount = getPlayerData(client).payDayAmount + payout; messageDiscordEventChannel(`💼 ${getCharacterFullName(client)} finished the ${jobRouteData.name} route for the ${getJobData(jobId).name} job and earned ${getCurrencyString(jobRouteData.pay)}!`); messagePlayerSuccess(client, replaceJobRouteStringsInMessage(jobRouteData.finishMessage, jobId, jobRouteData.index)); stopReturnToJobVehicleCountdown(client); sendPlayerStopJobRoute(client); respawnVehicle(getPlayerData(client).jobRouteVehicle); getPlayerData(client).jobRouteVehicle = false; getPlayerData(client).jobRoute = -1; getPlayerData(client).jobRouteLocation = -1; } // =========================================================================== function getNextLocationOnJobRoute(jobId, routeId, currentLocationId) { if (!isLastLocationOnJobRoute(jobId, routeId, currentLocationId)) { return currentLocationId + 1; } else { return getJobRouteData(jobId, routeId).locations.length - 1; } } // =========================================================================== function isLastLocationOnJobRoute(jobId, routeId, currentLocationId) { if (currentLocationId == getJobRouteData(jobId, routeId).locations.length - 1) { return true; } return false; } // =========================================================================== function getJobRouteFromParams(params, jobId) { if (isNaN(params)) { for (let i in getServerData().jobs[jobId].routes) { if (toLowerCase(getServerData().jobs[jobId].routes[i].name).indexOf(toLowerCase(params)) != -1) { return i; } } } else { if (typeof getServerData().jobs[jobId].routes[params] != "undefined") { return toInteger(params); } } return false; } // =========================================================================== function replaceJobRouteStringsInMessage(messageText, jobId, jobRouteId) { let tempJobRouteData = getJobRouteData(jobId, jobRouteId); let tempFind = `{JOBROUTENAME}`; let tempRegex = new RegExp(tempFind, 'g'); messageText = messageText.replace(tempRegex, tempJobRouteData.name); tempFind = `{JOBROUTEPAY}`; tempRegex = new RegExp(tempFind, 'g'); messageText = messageText.replace(tempRegex, `${getCurrencyString(tempJobRouteData.pay)}`); tempFind = `{JOBNAME}`; tempRegex = new RegExp(tempFind, 'g'); messageText = messageText.replace(tempRegex, getJobData(tempJobRouteData.jobIndex).name); return messageText; } // =========================================================================== function updateJobBlipsForPlayer(client) { if (!areServerElementsSupported()) { return false; } if (!getPlayerData(client)) { return false; } for (let i in getServerData().jobs) { for (let j in getServerData().jobs[i].locations) { if (getPlayerJob(client) == -1 || getPlayerJob(client) == i) { showElementForPlayer(getServerData().jobs[i].locations[j].blip, client); } else { hideElementForPlayer(getServerData().jobs[i].locations[j].blip, client); } } } } // =========================================================================== function getJobRouteLocationTypeFromParams(params) { for (let i in jobRouteLocationTypeNames) { if (toLowerCase(jobRouteLocationTypeNames[i]).indexOf(toLowerCase(params)) != -1) { return i; } } return -1; } // =========================================================================== function getLowestJobRank(jobIndex) { let lowestRank = 0; for (let i in getServerData().jobs[jobIndex].ranks) { if (getJobRankData(jobIndex, i).level < getJobRankData(jobIndex, lowestRank).level) { lowestRank = i; } } return lowestRank; } // =========================================================================== function getHighestJobRank(jobIndex) { let highestRank = 0; for (let i in getServerData().jobs[jobIndex].ranks) { if (getJobRankData(jobIndex, i).level > getJobRankData(jobIndex, highestRank).level) { highestRank = i; } } return highestRank; } // =========================================================================== function createJobRouteLocationMarker(jobIndex, jobRouteIndex, jobRouteLocationIndex) { let marker = null; if (isGameFeatureSupported("sphere")) { marker = createGameSphere(getJobRouteLocationData(jobIndex, jobRouteIndex, jobRouteLocationIndex).position, getGlobalConfig().jobRouteLocationSphereRadius, getJobData(jobIndex).colour); setElementOnAllDimensions(marker, false); setElementShownByDefault(marker, false); setElementDimension(marker, getGameConfig().mainWorldDimension[getGame()]); if (isGameFeatureSupported("interior")) { setElementInterior(marker, getGameConfig().mainWorldDimension[getGame()]); } } else { marker = getJobRouteLocationData(jobIndex, jobRouteIndex, jobRouteLocationIndex).marker = createGamePickup(getGameConfig().pickupModels[getGame()].Misc, getJobRouteLocationData(jobIndex, jobRouteIndex, jobRouteLocationIndex).position, getGameConfig().pickupTypes[getGame()].job); setElementOnAllDimensions(marker, false); setElementShownByDefault(marker, false); setElementDimension(marker, getGameConfig().mainWorldDimension[getGame()]); if (isGameFeatureSupported("interior")) { setElementInterior(marker, getGameConfig().mainWorldDimension[getGame()]); } } if (marker != null) { getJobRouteLocationData(jobIndex, jobRouteIndex, jobRouteLocationIndex).marker = marker; } } // =========================================================================== function createAllJobRouteLocationMarkers() { for (let i in getServerData().jobs) { for (let j in getServerData().jobs[i].routes) { for (let k in getServerData().jobs[i].routes[j].locations) { createJobRouteLocationMarker(i, j, k); } } } } // ===========================================================================