// plsyer obj_vars // --------------- // newbie_handoff.started // newbie_handoff.tour // newbie_handoff.tour.bank // newbie_handoff.tour.bank.waypoint // newbie_handoff.tour.cloning_center // newbie_handoff.tour.cloning_center.waypoint // newbie_handoff.tour.hospital // newbie_handoff.tour.hospital.waypoint // newbie_handoff.tour.cantina // newbie_handoff.tour.cantina.waypoint // newbie_handoff.tour.skill_trainer // newbie_handoff.tour.skill_trainer.waypoint // newbie_handoff.crafting // newbie_handoff.crafting.started // newbie_handoff.crafting.type // newbie_handoff.mission // newbie_handoff.mission.gig // newbie_handoff.mission.gig.type // newbie_handoff.mission.gig.loc // newbie_handoff.mission.gig.obj // newbie_handoff.mission.gig.duration // newbie_handoff.mission.gig.start // newbie_handoff.mission.survey // newbie_handoff.mission.survey.type // newbie_handoff.mission.survey.loc // newbie_handoff.mission.survey.resource // newbie_handoff.mission.survey.efficiency // newbie_handoff.mission.destroy // newbie_handoff.mission.destroy.type // newbie_handoff.mission.destroy.loc // newbie_handoff.mission.destroy.npc // newbie_handoff.mission.destroy.npc_id // newbie_handoff.events // newbie_handoff.events.earned_skill // newbie_handoff.events.trained_skill // // npc target // ------------------ // newbie_handoff.mission.type // newbie_handoff.mission.player // // // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// include library.planetary_map; include library.locations; include library.utils; include library.prose; include library.create; include library.ai_lib; include library.regions; const int MAX_DESTROY_TARGETS = 10; const int MAX_SEARCH_RANGE = 500; //meters const string STF_PLANET_MAP_CAT = "map_loc_cat_n"; const string TARGET_DATATABLE = "datatables/newbie_handoff/destroy_targets.iff"; const string DATATABLE_HOLOCRON_EVENTS = "datatables/holocron/events.iff"; const string VAR_FIND_BASE = "find"; const string VAR_FIND_WAYPOINT = VAR_FIND_BASE + ".waypoint"; const string[] NPC_TYPES = {"artisan","bodyguard","businessman","bothan_diplomat","entertainer","explorer","farmer","gambler","info_broker","miner","medic","noble","pilot","scientist"}; const string_id SID_NEWBIE_MISSION_DESTROY_START = new string_id ("newbie_handoff/messages","destroy_mission_start"); const string_id SID_NEWBIE_MISSION_DESTROY_COMPLETE = new string_id ("newbie_handoff/messages","destroy_mission_complete"); const string_id PROSE_NEWBIE_MISSION_SURVEY_START = new string_id ("newbie_handoff/messages","survey_mission_start"); const string_id SID_NEWBIE_MISSION_SURVEY_COMPLETE = new string_id ("newbie_handoff/messages","survey_mission_complete"); const string_id SID_NEWBIE_MISSION_GIG_DANCE_START = new string_id ("newbie_handoff/messages","gig_mission_dance_start"); const string_id SID_NEWBIE_MISSION_GIG_MUSIC_START = new string_id ("newbie_handoff/messages","gig_mission_music_start"); const string_id SID_NEWBIE_MISSION_GIG_ARRIVAL = new string_id ("newbie_handoff/messages","gig_mission_arrival"); const string_id SID_NEWBIE_MISSION_GIG_COMPLETE = new string_id ("newbie_handoff/messages","gig_mission_complete"); const string_id PROSE_NEWBIE_MISSION_HEAL_START = new string_id ("newbie_handoff/messages","heal_mission_start"); const string_id PROSE_NEWBIE_MISSION_HEAL_ARRIVAL = new string_id ("newbie_handoff/messages","heal_mission_arrival"); const string_id SID_NEWBIE_MISSION_HEAL_COMPLETE = new string_id ("newbie_handoff/messages","heal_mission_complete"); const string_id SID_NEWBIE_MISSION_HEAL_MENU = new string_id ("newbie_handoff/messages","heal_mission_menu"); const string_id SID_NEWBIE_MISSION_HEAL_USE = new string_id ("newbie_handoff/messages","heal_mission_use"); const string_id SID_NEWBIE_MISSION_HEAL_NEED_TARGET = new string_id ("newbie_handoff/messages","heal_mission_need_target"); const string_id SID_NEWBIE_MISSION_HEAL_WRONG_TARGET = new string_id ("newbie_handoff/messages","heal_mission_wrong_target"); const string_id SID_NEWBIE_MISSION_HARVEST_START = new string_id ("newbie_handoff/messages","harvest_mission_start"); const string_id SID_NEWBIE_MISSION_HARVEST_KILL = new string_id ("newbie_handoff/messages","harvest_mission_target_dead"); const string_id SID_NEWBIE_MISSION_HARVEST_COMPLETE = new string_id ("newbie_handoff/messages","harvest_mission_complete"); trigger OnAttach () { if (isJedi(self)) return SCRIPT_CONTINUE; // messageTo (self, "startHandoff", null, (5 * 60), false); return SCRIPT_CONTINUE; } trigger OnSpeaking(string text) { if (!hasObjVar(self, "gm")) return SCRIPT_CONTINUE; location loc = getLocation(self); string arg; java.util.StringTokenizer st = new java.util.StringTokenizer(text); if(st.countTokens() > 0) { arg = st.nextToken(); } else { arg = text; } if(arg == null || arg.equals("")) return SCRIPT_CONTINUE; if (arg.equals("findBank")) { LOG ("newbie_handoff", "Atempting to find closest Bank"); messageTo (self, "tourBank", null, 0, false); } if (arg.equals("findCantina")) { LOG ("newbie_handoff", "Atempting to find closest Cantina"); messageTo (self, "tourCantina", null, 0, false); } if (arg.equals("findHospital")) { LOG ("newbie_handoff", "Atempting to find closest Hospital"); messageTo (self, "tourHospital", null, 0, false); } if (arg.equals("findSkillTrainer")) { LOG ("newbie_handoff", "Atempting to find closest Skill Trainer"); messageTo (self, "tourSkillTrainer", null, 0, false); } if (arg.equals("holocronProfession")) { LOG ("newbie_handoff", "Opening Holocron to my profession"); messageTo (self, "openHolocronToProfession", null, 0, false); } if (arg.equals("missionArtisan")) { LOG ("newbie_handoff", "Creating new Artisan Mission"); messageTo (self, "missionArtisanSurvey", null, 0, false); } if (arg.equals("missionDancer")) { LOG ("newbie_handoff", "Creating new Dance Mission"); messageTo (self, "missionEntertainerDanceGig", null, 0, false); } if (arg.equals("missionMusician")) { LOG ("newbie_handoff", "Creating new Music Mission"); messageTo (self, "missionEntertainerMusicGig", null, 0, false); } if (arg.equals("missionMedic")) { LOG ("newbie_handoff", "Creating new Medic Mission"); messageTo (self, "missionMedicHeal", null, 0, false); } if (arg.equals("missionBrawler")) { LOG ("newbie_handoff", "Creating new Brawler Mission"); messageTo (self, "missionBrawlerDestroy", null, 0, false); } if (arg.equals("missionMarksman")) { LOG ("newbie_handoff", "Creating new Marksman Mission"); messageTo (self, "missionMarksmanDestroy", null, 0, false); } if (arg.equals("missionScout")) { LOG ("newbie_handoff", "Creating new Scout Mission"); messageTo (self, "missionScoutHarvest", null, 0, false); } return SCRIPT_CONTINUE; } trigger OnArrivedAtLocation( string name ) { if ( name.equals("tour.bank") ) { // Open holocron to next section openHolocronToNewbiePage(self, "WelcomeToSWG.WhereDoIBegin.Exploring.FindBank.ArrivedBank"); clearHolocronDatapadEntry(self, name); } else if ( name.equals("tour.cloning_center") ) { // Open holocron to next section openHolocronToNewbiePage(self, "WelcomeToSWG.WhereDoIBegin.Exploring.FindCloning.ArrivedCloning"); clearHolocronDatapadEntry(self, name); } else if ( name.equals("tour.hospital") ) { // Open holocron to next section openHolocronToNewbiePage(self, "WelcomeToSWG.WhereDoIBegin.Exploring.FindHospital.ArrivedHospital"); clearHolocronDatapadEntry(self, name); } else if ( name.equals("tour.cantina") ) { // Open holocron to next section openHolocronToNewbiePage(self, "WelcomeToSWG.WhereDoIBegin.Exploring.FindCantina.ArrivedCantina"); clearHolocronDatapadEntry(self, name); } else if ( name.equals("tour.skill_trainer") ) { // Open holocron to next section openHolocronToNewbiePage(self, "WelcomeToSWG.WhereDoIBegin.Exploring.FindSkillTrainer.ArrivedSkillTrainer"); clearHolocronDatapadEntry(self, name); } else if ( name.equals("mission.destroy") ) { removeLocationTarget (name); } else if ( name.equals("mission.destroy.spawnGuy") ) { removeLocationTarget (name); // Spawn the NPC location spawnLoc = getLocationObjVar (self, "newbie_handoff.mission.destroy.loc"); string npcToSpawn = getStringObjVar (self, "newbie_handoff.mission.destroy.npc"); string missionType = getStringObjVar (self, "newbie_handoff.mission.destroy.type"); if (npcToSpawn == null) { debugSpeakMsg (self, "Can't find anyone to spawn"); return SCRIPT_CONTINUE; } obj_id npc = create.object (npcToSpawn, spawnLoc); // Save the npc id to the player to clean up later if needed setObjVar( self, "newbie_handoff.mission.destroy.npc_id", npc ); // Set its faction to the bountyTarget faction pvpSetAlignedFaction( npc, ##"bountytarget" ); // Set the player as the only person who can attack it pvpSetPermanentPersonalEnemyFlag( npc, self ); setObjVar( npc, "newbie_handoff.mission.type", missionType ); setObjVar( npc, "newbie_handoff.mission.player", self ); // Attach the control script to the NPC attachScript (npc, "holocron.destroy_target"); } else if ( name.equals("mission.harvest") ) { removeLocationTarget (name); } else if ( name.equals("mission.harvest.spawnGuy") ) { removeLocationTarget (name); // Spawn the NPC location spawnLoc = getLocationObjVar (self, "newbie_handoff.mission.harvest.loc"); string npcToSpawn = getStringObjVar (self, "newbie_handoff.mission.harvest.npc"); string missionType = getStringObjVar (self, "newbie_handoff.mission.harvest.type"); if (npcToSpawn == null) { debugSpeakMsg (self, "Can't find anyone to spawn"); return SCRIPT_CONTINUE; } obj_id npc = create.object (npcToSpawn, spawnLoc); // Save the npc id to the player to clean up later if needed setObjVar( self, "newbie_handoff.mission.harvest.npc_id", npc ); // Set its faction to the bountyTarget faction pvpSetAlignedFaction( npc, ##"bountytarget" ); // Set the player as the only person who can attack it pvpSetPermanentPersonalEnemyFlag( npc, self ); setObjVar( npc, "newbie_handoff.mission.type", missionType ); setObjVar( npc, "newbie_handoff.mission.player", self ); // Attach the control script to the NPC attachScript (npc, "holocron.destroy_target"); } else if ( name.equals("mission.gig") ) { removeLocationTarget (name); // Give the player a message that they arrived at the Cantina and should start their performance sendSystemMessage (self, SID_NEWBIE_MISSION_GIG_ARRIVAL); } else if ( name.equals("mission.heal") ) { removeLocationTarget (name); // Give the player a message that they arrived at the Cantina and should start their performance obj_id npc = getObjIdObjVar(self, "newbie_handoff.mission.heal.npc_id"); prose_package pp = prose.getPackage (PROSE_NEWBIE_MISSION_HEAL_ARRIVAL, npc); sendSystemMessageProse (self, pp); } else { clearHolocronDatapadEntry(self, name); } return SCRIPT_CONTINUE; } messageHandler startHandoff() { playMusic( self, "sound/tut_00_holocron.snd" ); openHolocronToNewbiePage(self, "WelcomeToSWG.WhereDoIBegin"); return SCRIPT_CONTINUE; } messageHandler disableNewbieHandoff() { setObjVar( self, "newbie_handoff.disabled", 1 ); return SCRIPT_CONTINUE; } messageHandler enableNewbieHandoff() { removeObjVar( self, "newbie_handoff.disabled" ); return SCRIPT_CONTINUE; } messageHandler tourBank() { // Clear any previous tour entries in the datapad if (hasObjVar(self, "newbie_handoff.tour.bank")) { clearHolocronDatapadEntry( self, "tour.bank" ); messageTo (self, "tourBank", null, 1f, false); return SCRIPT_CONTINUE; } // Locate the nearest Bank map_location destination = planetary_map.findClosestLocation( self, "bank", "" ); location loc = new location (destination.getX(), 0, destination.getY()); // Create "mission" waypoint to the Bank and succeed "mission" upon arrival obj_id waypoint = addHolocronDatapadWaypoint( self, "tour.bank", "City Tour: Bank", loc, 20); addHolocronWaypointPath(self, waypoint); closeHolocron(self); return SCRIPT_CONTINUE; } messageHandler tourCloningCenter() { // Clear any previous tour entries in the datapad if (hasObjVar(self, "newbie_handoff.tour.cloning_center")) { clearHolocronDatapadEntry( self, "tour.cloning_center" ); messageTo (self, "tourCloningCenter", null, 1f, false); return SCRIPT_CONTINUE; } clearHolocronDatapadEntry( self, "tour.cloning_center" ); // Locate the nearest Cloning Center map_location destination = planetary_map.findClosestLocation( self, "cloningfacility", "" ); location loc = new location (destination.getX(), 0, destination.getY()); // Create "mission" waypoint to the Cloning Center and succeed "mission" upon arrival obj_id waypoint = addHolocronDatapadWaypoint( self, "tour.cloning_center", "City Tour: Cloning Center", loc, 5); addHolocronWaypointPath(self, waypoint); closeHolocron(self); return SCRIPT_CONTINUE; } messageHandler tourHospital() { // Clear any previous tour entries in the datapad if (hasObjVar(self, "newbie_handoff.tour.hospital")) { clearHolocronDatapadEntry( self, "tour.hospital" ); messageTo (self, "tourHospital", null, 1f, false); return SCRIPT_CONTINUE; } string[] priSearchList = {"hospital", "medicalcenter"}; string[] secSearchList = {"tavern", "barracks"}; // Locate the nearest Hospital location loc = findClosestStructure(self, priSearchList, secSearchList); // Create "mission" waypoint to the Hospital and succeed "mission" upon arrival obj_id waypoint = addHolocronDatapadWaypoint( self, "tour.hospital", "City Tour: Hospital", loc, 5); addHolocronWaypointPath(self, waypoint); closeHolocron(self); return SCRIPT_CONTINUE; } messageHandler tourCantina() { // Clear any previous tour entries in the datapad if (hasObjVar(self, "newbie_handoff.tour.cantina")) { clearHolocronDatapadEntry( self, "tour.cantina" ); messageTo (self, "tourCantina", null, 1f, false); return SCRIPT_CONTINUE; } string[] priSearchList = {"cantina", "guild_theater", "hotel"}; string[] secSearchList = {"tavern", "barracks"}; // Locate the nearest Cantina location loc = findClosestStructure(self, priSearchList, secSearchList); // Create "mission" waypoint to the Cantina and succeed "mission" upon arrival obj_id waypoint = addHolocronDatapadWaypoint( self, "tour.cantina", "City Tour: Cantina", loc, 5); addHolocronWaypointPath(self, waypoint); closeHolocron(self); return SCRIPT_CONTINUE; } messageHandler tourSkillTrainer() { // Clear any previous tour entries in the datapad if (hasObjVar(self, "newbie_handoff.tour.skill_trainer")) { clearHolocronDatapadEntry( self, "tour.skill_trainer" ); messageTo (self, "tourSkillTrainer", null, 1f, false); return SCRIPT_CONTINUE; } // Determine the correct Skill Trainer to take the player to based on their starting profession string profession = getStartingProfession( self ); string trainer_type = getTrainerType( profession ); LOG ("newbie_handoff", "Looking for trainer: " + profession + ", " + trainer_type); // Locate the correct trainer map_location destination = planetary_map.findClosestLocation( self, "trainer", trainer_type ); if ( destination == null) return SCRIPT_CONTINUE; location loc = new location (destination.getX(), 0, destination.getY()); // Create "mission" waypoint to the Skill Trainer and succeed "mission" upon arrival obj_id waypoint = addHolocronDatapadWaypoint( self, "tour.skill_trainer", "City Tour: Skill Trainer", loc, 5 ); addHolocronWaypointPath(self, waypoint); closeHolocron(self); return SCRIPT_CONTINUE; } messageHandler openHolocronToProfession() { // Find out the player's profession string profession = getStartingProfession( self ); profession = getSimpleProfession( profession ); profession = toUpper( profession, 0); // Open the Holocron to the starting section for that profession string page = "WelcomeToSWG.WhereDoIBegin.Professions.Playing" + profession; openHolocronToNewbiePage( self, page ); return SCRIPT_CONTINUE; } messageHandler missionArtisanSurvey() { // Clear any previous mission entries in the datapad if (hasObjVar(self, "newbie_handoff.mission.survey")) { clearHolocronDatapadEntry( self, "mission.survey" ); messageTo (self, "missionArtisanSurvey", null, 1f, false); return SCRIPT_CONTINUE; } const int MAX_RESOURCES = 10; // Start a simple survey mission for beginning Artisans obj_id[] resource = new obj_id[MAX_RESOURCES]; float[] efficiency = new float[MAX_RESOURCES]; obj_id resourceMax = null; float efficiencyMax = 0; // Locate a nearby resource to survey for ///////////////////////////////////////////////////////////////////////////////// // This should be simplified once I can get a better function call from Calan ///////////////////////////////////////////////////////////////////////////////// int resourceCount = 0; location here = getLocation(self); for (int x = 0; x < 50; x++) { obj_id curResource = pickRandomNonDepeletedResource( "mineral" ); float curEfficiency = getResourceEfficiency( curResource, here ); if ((curEfficiency > 0.4) && (curEfficiency < 0.55)) { resource[resourceCount] = curResource; efficiency[resourceCount] = curEfficiency; resourceCount++; } if ((curEfficiency > efficiencyMax) && (curEfficiency < 0.55)) { resourceMax = curResource; efficiencyMax = curEfficiency; } if (resourceCount >= MAX_RESOURCES) break; } int randResource = rand(0, resourceCount-1); obj_id targetResource = resource[randResource]; float targetEfficiency = efficiency[randResource]; if (resourceCount == 0) { randResource = -1; targetResource = resourceMax; targetEfficiency = efficiencyMax; } targetEfficiency += (0.7 - targetEfficiency) * 0.15f; LOG ("newbie_handoff", "Survey Mission Create: Using Resource #" + randResource + " of " + resourceCount + " resources."); LOG ("newbie_handoff", " Target Resource: " + targetResource + "; Target Efficiency: " + targetEfficiency); // Create the datapad misison object addHolocronDatapadEntry( self, "mission.survey", "Artisan Survey Mission" ); // Store the resource type and amount to be surveyed for on the player setObjVar( self, "newbie_handoff.mission.survey.type", "artisan" ); setObjVar( self, "newbie_handoff.mission.survey.loc", here ); setObjVar( self, "newbie_handoff.mission.survey.resource", targetResource ); setObjVar( self, "newbie_handoff.mission.survey.efficiency", targetEfficiency ); closeHolocron(self); // Get the name of the resource to survey for and tell the player string resourceName = "INSERT NAME HERE"; string resourceClass = "INSERT CLASS HERE"; int resourceEfficiency = (int) (targetEfficiency * 100); prose_package pp = prose.getPackage (PROSE_NEWBIE_MISSION_SURVEY_START, null, null, null, null, resourceName, null, null, resourceClass, null, resourceEfficiency, 0f); sendSystemMessageProse (self, pp); return SCRIPT_CONTINUE; } messageHandler missionEntertainerDanceGig() { // Clear any previous mission entries in the datapad if (hasObjVar(self, "newbie_handoff.mission.gig")) { clearHolocronDatapadEntry( self, "mission.gig" ); messageTo (self, "missionEntertainerDanceGig", null, 1f, false); return SCRIPT_CONTINUE; } // Start a simple dance gig mission for beginning Entertainers // Locate the cantina and send the player there map_location destination = planetary_map.findClosestLocation( self, "cantina", "" ); location loc = new location (destination.getX(), 0, destination.getY()); // Set a waypoint to the destination addHolocronDatapadWaypoint( self, "mission.gig", "Entertainer Dance Mission", loc, 25 ); // Store the gig mission data on the player setObjVar( self, "newbie_handoff.mission.gig.type", "dancer" ); setObjVar( self, "newbie_handoff.mission.gig.loc", loc ); setObjVar( self, "newbie_handoff.mission.gig.obj", destination.getLocationId() ); setObjVar( self, "newbie_handoff.mission.gig.duration", 120 ); closeHolocron(self); sendSystemMessage (self, SID_NEWBIE_MISSION_GIG_DANCE_START); return SCRIPT_CONTINUE; } messageHandler missionEntertainerMusicGig() { // Clear any previous mission entries in the datapad if (hasObjVar(self, "newbie_handoff.mission.gig")) { clearHolocronDatapadEntry( self, "mission.gig" ); messageTo (self, "missionEntertainerMusicGig", null, 1f, false); return SCRIPT_CONTINUE; } // Start a simple music gig mission for beginning Entertainers // Locate the cantina and send the player there map_location destination = planetary_map.findClosestLocation( self, "cantina", "" ); location loc = new location (destination.getX(), 0, destination.getY()); // Set a waypoint to the destination addHolocronDatapadWaypoint( self, "mission.gig", "Entertainer Music Mission", loc, 25 ); // Store the gig mission data on the player setObjVar( self, "newbie_handoff.mission.gig.type", "musician" ); setObjVar( self, "newbie_handoff.mission.gig.loc", loc ); setObjVar( self, "newbie_handoff.mission.gig.obj", destination.getLocationId() ); setObjVar( self, "newbie_handoff.mission.gig.duration", 120 ); closeHolocron(self); sendSystemMessage (self, SID_NEWBIE_MISSION_GIG_MUSIC_START); return SCRIPT_CONTINUE; } messageHandler missionMedicHeal() { // Clear any previous mission entries in the datapad if (hasObjVar(self, "newbie_handoff.mission.heal")) { clearHolocronDatapadEntry( self, "mission.heal" ); messageTo (self, "missionMedicHeal", null, 1f, false); return SCRIPT_CONTINUE; } // Start a simple heal mission for beginning Medics string planet = getCurrentSceneName(); region city = locations.getCityRegion( getLocation(self) ); if ( city == null || planet == null ) return SCRIPT_CONTINUE; // Get a good location for the target NPC location destination = null; int x = 0; while (x < 10) { LOG ("newbie_handoff", "Medic Mission Create: Attepmt #" + (x+1) + "; Distance=" + (10+(x*10))); destination = locations.getGoodCityLocation(city, planet); if (destination != null) break; x += 1; } if ( destination == null ) return SCRIPT_CONTINUE; // Set a waypoint to the destination addHolocronDatapadWaypoint( self, "mission.heal", "Medic Heal Mission", destination, 5 ); // Create the NPC and initialize obj_id npc = create.object(NPC_TYPES[rand(0,NPC_TYPES.length-1)], destination); setObjVar( npc, "newbie_handoff.mission.type", "medic" ); setObjVar( npc, "newbie_handoff.mission.player", self ); // Attach the control script to the NPC attachScript (npc, "holocron.heal_target"); // Create the medicine and initialize obj_id inv = getObjectInSlot(self, "inventory"); obj_id med = createObject("object/tangible/medicine/newbie_heal_mission_medicine.iff", inv, ""); setObjVar( med, "newbie_handoff.mission.type", "medic" ); setObjVar( med, "newbie_handoff.mission.player", self ); // Store the location, med id and the npc id on the player setObjVar( self, "newbie_handoff.mission.heal.type", "medic" ); setObjVar( self, "newbie_handoff.mission.heal.loc", destination ); setObjVar( self, "newbie_handoff.mission.heal.npc_id", npc ); setObjVar( self, "newbie_handoff.mission.heal.med_id", med ); closeHolocron(self); prose_package pp = prose.getPackage (PROSE_NEWBIE_MISSION_HEAL_START, npc); sendSystemMessageProse (self, pp); return SCRIPT_CONTINUE; } messageHandler missionBrawlerDestroy() { // Clear any previous mission entries in the datapad if (hasObjVar(self, "newbie_handoff.mission.destroy")) { clearHolocronDatapadEntry( self, "mission.destroy" ); messageTo (self, "missionBrawlerDestroy", null, 1f, false); return SCRIPT_CONTINUE; } // Start a simple destroy mission for beginning Brawlers region city = locations.getCityRegion( getLocation(self) ); if ( city == null ) return SCRIPT_CONTINUE; // Get a good location for the target NPC location destination = null; int x = 0; while (x < 10) { LOG ("newbie_handoff", "Brawler Mission Create: Attepmt #" + (x+1) + "; Distance=" + (10+(x*10))); destination = locations.getGoodLocationOutsideOfRegion(city, 30f, 30f, 10 + (x * 10), false, true); if (destination != null) break; x += 1; } if ( destination == null ) return SCRIPT_CONTINUE; // Set a waypoint to the destination addHolocronDatapadWaypoint( self, "mission.destroy", "Brawler Destroy Mission", destination, 25 ); // Set the location triggers for when the player gets near the destination addLocationTarget ("mission.destroy.spawnGuy", destination, 100); // Store the location and the npc to spawn on the player setObjVar( self, "newbie_handoff.mission.destroy.type", "brawler" ); setObjVar( self, "newbie_handoff.mission.destroy.loc", destination ); string npc = determineDestroyTarget( self ); setObjVar( self, "newbie_handoff.mission.destroy.npc", npc ); closeHolocron(self); sendSystemMessage (self, SID_NEWBIE_MISSION_DESTROY_START); return SCRIPT_CONTINUE; } messageHandler missionMarksmanDestroy() { // Clear any previous mission entries in the datapad if (hasObjVar(self, "newbie_handoff.mission.destroy")) { clearHolocronDatapadEntry( self, "mission.destroy" ); messageTo (self, "missionMarksmanDestroy", null, 1f, false); return SCRIPT_CONTINUE; } // Start a simple destroy mission for beginning Marksman region city = locations.getCityRegion( getLocation(self) ); if ( city == null ) return SCRIPT_CONTINUE; // Get a good location for the target NPC location destination = null; int x = 0; while (x < 10) { LOG ("newbie_handoff", "Marksman Mission Create: Attepmt #" + (x+1) + "; Distance=" + (10+(x*10))); destination = locations.getGoodLocationOutsideOfRegion(city, 30f, 30f, 10 + (x * 10), false, true); if (destination != null) break; x += 1; } if ( destination == null ) return SCRIPT_CONTINUE; // Set a waypoint to the destination addHolocronDatapadWaypoint( self, "mission.destroy", "Marksman Destroy Mission", destination, 25 ); // Set the location triggers for when the player gets near the destination addLocationTarget ("mission.destroy.spawnGuy", destination, 100); // Store the location and the npc to spawn on the player setObjVar( self, "newbie_handoff.mission.destroy.type", "marksman" ); setObjVar( self, "newbie_handoff.mission.destroy.loc", destination ); string npc = determineDestroyTarget( self ); setObjVar( self, "newbie_handoff.mission.destroy.npc", npc ); closeHolocron(self); sendSystemMessage (self, SID_NEWBIE_MISSION_DESTROY_START); return SCRIPT_CONTINUE; } messageHandler missionScoutHarvest() { // Clear any previous mission entries in the datapad if (hasObjVar(self, "newbie_handoff.mission.harvest")) { clearHolocronDatapadEntry( self, "mission.harvest" ); messageTo (self, "missionScoutHarvest", null, 1f, false); return SCRIPT_CONTINUE; } // Start a simple harvest mission for beginning Scouts region city = locations.getCityRegion( getLocation(self) ); if ( city == null) return SCRIPT_CONTINUE; // Get a good location for the target NPC location destination = null; int x = 0; while (x < 10) { LOG ("newbie_handoff", "Scout Mission Create: Attepmt #" + (x+1) + "; Distance=" + (10+(x*10))); destination = locations.getGoodLocationOutsideOfRegion(city, 30f, 30f, 10 + (x * 10), false, true); if (destination != null) break; x += 1; } if ( destination == null ) return SCRIPT_CONTINUE; // Set a waypoint to the destination addHolocronDatapadWaypoint( self, "mission.harvest", "Scout Harvest Mission", destination, 25 ); // Set the location triggers for when the player gets near the destination addLocationTarget ("mission.harvest.spawnGuy", destination, 100); // Store the location and the npc to spawn on the player setObjVar( self, "newbie_handoff.mission.harvest.type", "scout" ); setObjVar( self, "newbie_handoff.mission.harvest.loc", destination ); string npc = determineDestroyTarget( self ); setObjVar( self, "newbie_handoff.mission.harvest.npc", npc ); closeHolocron(self); sendSystemMessage (self, SID_NEWBIE_MISSION_HARVEST_START); return SCRIPT_CONTINUE; } void commandOpenCraftingTool( obj_id player ) { // Initialize the obj_var crafting data // Open the generic crafting tool automatically for the player } void prototypeCompleted() { // Crafting finished go back to the correct location in the Holocron } commandHandler eventEarnedSkillBox() { if (isSpaceScene()) return SCRIPT_CONTINUE;//fuck that! // This event trigger opens the Holocron the very first time the player earns enough xp to purchase a skill box dictionary holocronParams = new dictionary(); holocronParams.put ("eventName","EarnedSkillBox"); messageTo(self, "handleHolocronEvent", holocronParams, 0, false); return SCRIPT_CONTINUE; } messageHandler eventTrainedSkillBox() { // This event trigger opens the Holocron the very first time the player trains a new skill box dictionary holocronParams = new dictionary(); holocronParams.put ("eventName","TrainedSkillBox"); messageTo(self, "handleHolocronEvent", holocronParams, 0, false); return SCRIPT_CONTINUE; } messageHandler handleHolocronEvent() { if (isSpaceScene()) return SCRIPT_CONTINUE; // moohahahah // Make sure the Holocron pop-ups haven't been disabled if (hasObjVar(self, "newbie_handoff.disabled")) return SCRIPT_CONTINUE; if (isJedi(self)) return SCRIPT_CONTINUE; string event = params.getString( "eventName" ); int eventFlag = dataTableGetInt(DATATABLE_HOLOCRON_EVENTS, event, "eventFlag"); string eventEntry = dataTableGetString(DATATABLE_HOLOCRON_EVENTS, event, "eventEntry"); if ((eventFlag == -1) || (eventEntry == null) || (eventEntry.equals(""))) { return SCRIPT_CONTINUE; } int bitFieldNum = (int) eventFlag / 32; int bitFlag = eventFlag % 32; int bitField = getIntObjVar(self, "newbie_handoff.events.bitField"+bitFieldNum); if (!utils.checkBit(bitField, bitFlag)) { bitField = utils.setBit(bitField, bitFlag); setObjVar(self, "newbie_handoff.events.bitField"+bitFieldNum, bitField); openHolocronToNewbiePage(self, eventEntry); } return SCRIPT_CONTINUE; } messageHandler missionSurveyComplete() { LOG ("newbie_handoff", "Survey Mission Complete"); LOG ("newbie_handoff", " Clearing Mission Data"); clearHolocronDatapadEntry(self, "mission.survey"); sendSystemMessage (self, SID_NEWBIE_MISSION_SURVEY_COMPLETE); //messageTo (self, "openHolocronAfterArtisanMission", null, 0, false); LOG ("newbie_handoff", "Opening Holocron to Artisan Survey Complete Section"); openHolocronToNewbiePage(self, "WelcomeToSWG.WhereDoIBegin.Professions.PlayingArtisan.Resources.Survey.Complete"); return SCRIPT_CONTINUE; } messageHandler missionGigComplete() { LOG ("newbie_handoff", "Gig Mission Complete"); LOG ("newbie_handoff", " Clearing Mission Data"); clearHolocronDatapadEntry(self, "mission.gig"); sendSystemMessage (self, SID_NEWBIE_MISSION_GIG_COMPLETE); messageTo (self, "openHolocronAfterGigMission", null, 5, false); return SCRIPT_CONTINUE; } messageHandler missionHealComplete() { LOG ("newbie_handoff", "Heal Mission Complete"); LOG ("newbie_handoff", " Clearing Mission Data"); clearHolocronDatapadEntry(self, "mission.heal"); sendSystemMessage (self, SID_NEWBIE_MISSION_HEAL_COMPLETE); messageTo (self, "openHolocronAfterHealMission", null, 5, false); return SCRIPT_CONTINUE; } messageHandler missionDestroyComplete() { LOG ("newbie_handoff", "Destroy Mission Complete"); LOG ("newbie_handoff", " Clearing Location Targets"); clearHolocronDatapadEntry(self, "mission.destroy"); string profession = params.getString( "type" ); LOG ("newbie_handoff", " Retreiving destroy mission type: " + profession); if ( profession.equals("brawler") ) { LOG ("newbie_handoff", " Sending messeage to open Holocron"); sendSystemMessage (self, SID_NEWBIE_MISSION_DESTROY_COMPLETE); messageTo (self, "openHolocronAfterBrawlerMission", null, 5, false); } else { LOG ("newbie_handoff", " Sending messeage to open Holocron"); sendSystemMessage (self, SID_NEWBIE_MISSION_DESTROY_COMPLETE); messageTo (self, "openHolocronAfterMarksmanMission", null, 5, false); } return SCRIPT_CONTINUE; } messageHandler missionHarvestTargetDead() { LOG ("newbie_handoff_harvest", "Creature Killed: Telling player to harvest."); sendSystemMessage (self, SID_NEWBIE_MISSION_HARVEST_KILL); return SCRIPT_CONTINUE; } messageHandler missionHarvestComplete() { LOG ("newbie_handoff", "Harvest Mission Complete"); LOG ("newbie_handoff", " Clearing Location Targets"); clearHolocronDatapadEntry(self, "mission.harvest"); LOG ("newbie_handoff", " Sending messeage to open Holocron"); sendSystemMessage (self, SID_NEWBIE_MISSION_HARVEST_COMPLETE); messageTo (self, "openHolocronAfterScoutMission", null, 5, false); return SCRIPT_CONTINUE; } messageHandler openHolocronAfterGigMission() { LOG ("newbie_handoff", "Opening Holocron to Entertainer Gig Complete Section"); openHolocronToNewbiePage(self, "WelcomeToSWG.WhereDoIBegin.Professions.PlayingEntertainer.Instruments.Gig.Complete"); return SCRIPT_CONTINUE; } messageHandler openHolocronAfterHealMission() { LOG ("newbie_handoff", "Opening Holocron to Medic Heal Complete Section"); openHolocronToNewbiePage(self, "WelcomeToSWG.WhereDoIBegin.Professions.PlayingMedic"); return SCRIPT_CONTINUE; } messageHandler openHolocronAfterBrawlerMission() { LOG ("newbie_handoff", "Opening Holocron to Brawler Destroy Complete Section"); if ( ai_lib.isInCombat( self ) ) { LOG ("newbie_handoff", " Still in combat, wait 15 seconds"); messageTo (self, "openHolocronAfterBrawlerMission", null, 15, false); } else { openHolocronToNewbiePage(self, "WelcomeToSWG.WhereDoIBegin.Professions.PlayingBrawler.MeleeTactics.Destroy.Complete"); } return SCRIPT_CONTINUE; } messageHandler openHolocronAfterMarksmanMission() { LOG ("newbie_handoff", "Opening Holocron to Marksman Destroy Complete Section"); if ( ai_lib.isInCombat( self ) ) { LOG ("newbie_handoff", " Still in combat, wait 15 seconds"); messageTo (self, "openHolocronAfterMarksmanMission", null, 15, false); } else { openHolocronToNewbiePage(self, "WelcomeToSWG.WhereDoIBegin.Professions.PlayingMarksman.RangedTactics.Destroy.Complete"); } return SCRIPT_CONTINUE; } messageHandler openHolocronAfterScoutMission() { LOG ("newbie_handoff", "Opening Holocron to Scout Harvest Complete Section"); if ( ai_lib.isInCombat( self ) ) { LOG ("newbie_handoff", " Still in combat, wait 15 seconds"); messageTo (self, "openHolocronAfterScoutMission", null, 15, false); } else { openHolocronToNewbiePage(self, "WelcomeToSWG.WhereDoIBegin.Professions.PlayingScout.Harvesting.Harvest.Complete"); } return SCRIPT_CONTINUE; } trigger OnWaypointDestroyed(obj_id waypoint) { LOG ("newbie_handoff", " Trying to remove data for Waypoint: " + waypoint); if (hasObjVar(self, "newbie_handoff.waypoint." + waypoint)) { dictionary params = new dictionary(); params.put("waypoint", waypoint); params.put("name", getStringObjVar(self, "newbie_handoff.waypoint." + waypoint)); params.put("index", -1); LOG ("newbie_handoff", " Sending message to remove data"); messageTo (self, "removeDatapadEntryData", params, 0, false); } else { resizeable obj_id[] waypointIds = getResizeableObjIdArrayObjVar(self, "newbie_handoff.waypoint.idList"); resizeable string[] waypointNames = getResizeableStringArrayObjVar(self, "newbie_handoff.waypoint.nameList"); int idx = findWaypointIndex(waypointIds, waypoint); if (idx != -1) { dictionary params = new dictionary(); params.put("waypoint", waypoint); params.put("name", waypointNames[idx]); params.put("index", idx); LOG ("newbie_handoff", " Sending message to remove data"); messageTo (self, "removeDatapadEntryData", params, 0, false); } } return SCRIPT_CONTINUE; } messageHandler removeDatapadEntryData() { string name = params.getString("name"); obj_id waypoint = params.getObjId("waypoint"); int index = params.getInt("index"); LOG ("newbie_handoff", "Destroying Datapad Entry " + name); if ( name.equals("mission.destroy") || name.equals("mission.harvest") || name.equals("mission.heal") ) { LOG ("newbie_handoff", " Cleaning up spawned stuff"); obj_id spawnedNpc = getObjIdObjVar( self, name + ".npc_id" ); if ( isIdValid(spawnedNpc) ) { destroyObject( spawnedNpc ); } } if ( name.equals("mission.destroy") || name.equals("mission.harvest") || name.equals("mission.heal") ) { LOG ("newbie_handoff", " Removing mission spawner trigger"); removeLocationTarget( name + ".spawnGuy" ); } LOG ("newbie_handoff", " Removing obj_var data"); if ( hasObjVar( self, "newbie_handoff." + name ) ) { LOG ("newbie_handoff", " Removing " + name + " data."); removeObjVar( self, "newbie_handoff." + name ); } if (waypoint != null) { LOG ("newbie_handoff", " Removing waypoint data."); if (index != -1) { resizeable obj_id[] waypointIds = getResizeableObjIdArrayObjVar(self, "newbie_handoff.waypoint.idList"); resizeable string[] waypointNames = getResizeableStringArrayObjVar(self, "newbie_handoff.waypoint.nameList"); waypointIds = utils.removeElementAt(waypointIds, index); waypointNames = utils.removeElementAt(waypointNames, index); if (waypointIds.length > 0 && waypointNames.length > 0) { setObjVar(self, "newbie_handoff.waypoint.idList", waypointIds); setObjVar(self, "newbie_handoff.waypoint.nameList", waypointNames); } else { removeObjVar(self, "newbie_handoff.waypoint.idList"); removeObjVar(self, "newbie_handoff.waypoint.nameList"); } } else { if (hasObjVar(self, "newbie_handoff.waypoint." + waypoint)) removeObjVar(self, "newbie_handoff.waypoint." + waypoint); } } return SCRIPT_CONTINUE; } obj_id addHolocronDatapadWaypoint( obj_id player, string name, string display, location loc, float radius ) { LOG ("newbie_handoff", "Creating Waypoint: '" + display + "' in Datapad..."); //Create the waypoint and location target obj_id waypoint = createWaypointInDatapad(player, loc); setWaypointName(waypoint, display); addLocationTarget(name, loc, radius); // Activate the waypoint setWaypointActive( waypoint, true); // Save the waypoint info on the player setObjVar( player, "newbie_handoff." + name + ".waypoint", waypoint ); resizeable obj_id[] waypointIds = new obj_id[0]; resizeable string[] waypointNames = new string[0]; if (hasObjVar(player, "newbie_handoff.waypoint.idList")) { waypointIds = getResizeableObjIdArrayObjVar(player, "newbie_handoff.waypoint.idList"); waypointNames = getResizeableStringArrayObjVar(player, "newbie_handoff.waypoint.nameList"); } waypointIds = utils.addElement(waypointIds, waypoint); waypointNames = utils.addElement(waypointNames, name); if(waypointIds.length > 0 && waypointNames.length > 0) { // Check for zero length arrays setObjVar(player, "newbie_handoff.waypoint.idList", waypointIds); setObjVar(player, "newbie_handoff.waypoint.nameList", waypointNames); } return waypoint; } obj_id addHolocronDatapadEntry( obj_id player, string name, string display ) { LOG ("newbie_handoff", "Creating Entry: '" + display + "' in Datapad..."); //Create the waypoint and location target obj_id datapad = getObjectInSlot( player, "datapad" ); obj_id entry = createObject( "object/intangible/holocron/newbie_mission.iff", datapad, "" ); setName ( entry, display ); LOG ("newbie_handoff", " Created entry: " + entry + " in datapad object: " + datapad); LOG ("newbie_handoff", " Datapad contains object: " + utils.isNestedWithin( entry, datapad )); // Save the waypoint obj_id on the player setObjVar( player, "newbie_handoff." + name + ".dataEntry", entry ); // Save the pertinent data and attach script to waypoint to properly handle deletion attachScript( entry, "holocron.datapad_entry" ); setObjVar( entry, "newbie_handoff.name", name ); setObjVar( entry, "newbie_handoff.player", player ); return entry; } void clearHolocronDatapadEntry(obj_id player, string name) { if (hasObjVar(player, "newbie_handoff." + name + ".dataEntry")) { obj_id dataEntry = getObjIdObjVar(player, "newbie_handoff." + name + ".dataEntry"); if (isIdValid(dataEntry)) { destroyObject(dataEntry); } //removeObjVar(player, "newbie_handoff." + name + ".dataEntry"); return; } if (hasObjVar(player, "newbie_handoff." + name + ".waypoint")) { obj_id waypoint = getObjIdObjVar(player, "newbie_handoff." + name + ".waypoint"); //setWaypointVisible(waypoint, false); if (isIdValid(waypoint)) { setWaypointActive(waypoint, false); destroyWaypointInDatapad(waypoint, player); } removeLocationTarget(name); //removeObjVar(player, "newbie_handoff." + name + ".waypoint"); return; } } void addHolocronWaypointPath(obj_id player, obj_id waypoint) { if ( utils.hasScriptVar(player, "hasClientPath") ) { destroyClientPath(player); obj_id oldWaypoint = utils.getObjIdScriptVar(player, "hasClientPath"); if (isIdValid(oldWaypoint)) { destroyWaypointInDatapad(oldWaypoint, player); } utils.removeScriptVar(player, "hasClientPath"); } location here = getLocation(player); location there = getWaypointLocation(waypoint); region[] hereCity = getRegionsWithGeographicalAtPoint(here, regions.GEO_CITY); region[] thereCity = getRegionsWithGeographicalAtPoint(there, regions.GEO_CITY); if ( hereCity != null && hereCity.length > 0 && thereCity != null && thereCity.length > 0 ) { boolean areInSameCity = false; for ( int a = 0; a < hereCity.length; a++ ) { for ( int b = 0; b < thereCity.length; b++ ) { if ( (hereCity[a].getName()).equals(thereCity[b].getName()) ) { areInSameCity = true; break; } } if ( areInSameCity ) break; } if ( areInSameCity ) { there.y = getHeightAtLocation(there.x, there.z); location start = here; if ( isIdValid(start.cell) ) start = getBuildingEjectLocation(getTopMostContainer(player)); //debugSpeakMsg(player, "Attempting to create client path..."); if ( !createClientPath(player, start, there) ) { sendSystemMessageTestingOnly(player, "The system was unable to create a client path for you."); } else { if ( here.cell != start.cell ) sendSystemMessageTestingOnly(player, "Your find path has been started near the entrance of the structure you are currenly in."); utils.setScriptVar(player, "hasClientPath", waypoint); } } } } int findWaypointIndex(resizeable obj_id[] idList, obj_id waypoint) { if (idList != null && idList.length > 0) { for (int i = 0; i < idList.length; i++) { if (idList[i] == waypoint) return i; } } return -1; } void openHolocronToNewbiePage( obj_id player, string page ) { if ( !hasObjVar( player, "newbie_handoff.disabled" ) ) { openHolocronToPage(player, page); } } location findClosestStructure(obj_id player, string[] priSearchList, string[] secSearchList) { float priDist = Float.POSITIVE_INFINITY; location priLoc = null; float secDist = Float.POSITIVE_INFINITY; location secLoc = null; for (int i = 0; i < priSearchList.length; i++) { java.util.StringTokenizer st = new java.util.StringTokenizer(priSearchList[i], "_"); string cat = st.nextToken(); string sub = ""; if ( st.hasMoreTokens() ) { sub = st.nextToken(); } map_location destination = planetary_map.findClosestLocation(player, cat, sub); if (destination == null) continue; location loc = new location (destination.getX(), 0, destination.getY()); float dist = utils.getDistance2D(getLocation(player), loc); if (dist < priDist) { priDist = dist; priLoc = loc; } } if (priDist < MAX_SEARCH_RANGE) return priLoc; for (int i = 0; i < secSearchList.length; i++) { java.util.StringTokenizer st = new java.util.StringTokenizer(secSearchList[i], "_"); string cat = st.nextToken(); string sub = ""; if ( st.hasMoreTokens() ) { sub = st.nextToken(); } map_location destination = planetary_map.findClosestLocation(player, cat, sub); if (destination == null) continue; location loc = new location (destination.getX(), 0, destination.getY()); float dist = utils.getDistance2D(getLocation(player), loc); if (dist < secDist) { secDist = dist; secLoc = loc; } } if (secDist < MAX_SEARCH_RANGE) return secLoc; if (priDist < secDist) return priLoc; else return secLoc; } string getStartingProfession( obj_id player ) { string[] skillList = getSkillListingForPlayer( player ); if ( skillList == null ) return (""); if ( skillList.length < 1 ) return (""); string skillName = null; for ( int i = 0; i < skillList.length; i++ ) { if ( skillList[i].endsWith("_novice") ) { skillName = skillList[i]; } } if ( (skillName == null) || (skillName.equals("")) ) return (""); string profession = getSkillProfession( skillName ); if ( profession == null ) return (""); return profession; } string getSimpleProfession( string profession ) { java.util.StringTokenizer st = new java.util.StringTokenizer(profession, "_"); string tmp = st.nextToken(); if ( st.hasMoreTokens() ) { tmp = st.nextToken(); } return tmp; } string getTrainerType( string profession ) { if ( profession == null || profession.equals("") ) return (""); string simpleProfession = getSimpleProfession( profession ); // string_id sid = new string_id( STF_PLANET_MAP_CAT, simpleProfession ); // string trainerType = utils.packStringId( sid ); return ("trainer_" + simpleProfession); } string determineDestroyTarget( obj_id player ) { // Find out what planet the player is on string planet = getCurrentSceneName(); // Find out what city the player is in string city = locations.getCityName( getLocation(player) ); // Load the valid targets for this planet/city combo from the datatable LOG ("newbie_handoff", "Seraching for destroy mission target at " + planet + ": " + city); string target = loadRandomDestroyTarget( planet, city ); return target; } string loadRandomDestroyTarget( string planet, string city ) { string[] targets = new string[MAX_DESTROY_TARGETS]; string[] entries = dataTableGetStringColumn( TARGET_DATATABLE, "strPlanet" ); if(entries == null || entries.length == 0) { // Should never happen LOG ("newbie_handoff", "WARNING: No targets defined for " + planet + ": " + city + ", using default target"); return dataTableGetString( TARGET_DATATABLE, 0, "strTarget" ); } LOG ("newbie_handoff", "Reading " + TARGET_DATATABLE + ":" + entries.length + "entries read."); int targetCount = 0; for (int i = 0; i < entries.length; i++) { if(entries[i] == null || entries[i].equals("")) { entries[i] = "nullPlanet"; } if (entries[i].equals(planet)) { if (dataTableGetString( TARGET_DATATABLE, i, "strCity" ).equals(city)) { targets[targetCount] = dataTableGetString( TARGET_DATATABLE, i, "strTarget" ); LOG ("newbie_handoff", "Possible target found: " + targets[targetCount]); targetCount++; if (targetCount >= MAX_DESTROY_TARGETS) { LOG ("newbie_handoff", "WARNING: Datatable contains more targets than MAX_DESTROY_TARGETS(" + MAX_DESTROY_TARGETS + ")"); break; } } } } if (targetCount == 0) { LOG ("newbie_handoff", "WARNING: No targets defined for " + planet + ": " + city + ", using default target"); return dataTableGetString( TARGET_DATATABLE, 0, "strTarget" ); } return targets[rand(0, targetCount-1)]; }