mirror of
https://github.com/ProjectSWGCore/Holocore.git
synced 2026-09-11 21:45:26 -04:00
Merge pull request #1491 from madsboddum/feature/quests/go-to-location
Added support for quest.task.ground.go_to_location
This commit is contained in:
+102
-1
@@ -1,5 +1,5 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2023 /// Project SWG /// www.projectswg.com *
|
||||
* Copyright (c) 2024 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
@@ -168,6 +168,37 @@ public class QuestLoader extends DataLoader {
|
||||
if (columns.contains("music_on_failure")) {
|
||||
musicOnFailure = set.getText("music_on_failure");
|
||||
}
|
||||
boolean createWaypoint = false;
|
||||
if (columns.contains("create_waypoint")) {
|
||||
createWaypoint = set.getBoolean("create_waypoint");
|
||||
}
|
||||
String planetName = null;
|
||||
if (columns.contains("planet_name")) {
|
||||
planetName = set.getText("planet_name");
|
||||
}
|
||||
double locationX = 0;
|
||||
if (columns.contains("location_x")) {
|
||||
locationX = set.getReal("location_x");
|
||||
}
|
||||
double locationY = 0;
|
||||
if (columns.contains("location_y")) {
|
||||
locationY = set.getReal("location_y");
|
||||
}
|
||||
double locationZ = 0;
|
||||
if (columns.contains("location_z")) {
|
||||
locationZ = set.getReal("location_z");
|
||||
}
|
||||
String waypointName = null;
|
||||
if (columns.contains("waypoint_name")) {
|
||||
waypointName = set.getText("waypoint_name");
|
||||
}
|
||||
double radius = 0;
|
||||
if (columns.contains("radius")) {
|
||||
String radiusText = set.getText("radius"); // Is seen as empty string if not set
|
||||
if (!radiusText.isBlank()) {
|
||||
radius = Double.parseDouble(radiusText);
|
||||
}
|
||||
}
|
||||
|
||||
QuestTaskInfo questTaskInfo = new QuestTaskInfo();
|
||||
|
||||
@@ -208,6 +239,13 @@ public class QuestLoader extends DataLoader {
|
||||
questTaskInfo.setMusicOnActivate(musicOnActivate);
|
||||
questTaskInfo.setMusicOnComplete(musicOnComplete);
|
||||
questTaskInfo.setMusicOnFailure(musicOnFailure);
|
||||
questTaskInfo.setCreateWaypoint(createWaypoint);
|
||||
questTaskInfo.setPlanetName(planetName);
|
||||
questTaskInfo.setLocationX(locationX);
|
||||
questTaskInfo.setLocationY(locationY);
|
||||
questTaskInfo.setLocationZ(locationZ);
|
||||
questTaskInfo.setWaypointName(waypointName);
|
||||
questTaskInfo.setRadius(radius);
|
||||
|
||||
questTaskInfos.add(questTaskInfo);
|
||||
}
|
||||
@@ -325,6 +363,13 @@ public class QuestLoader extends DataLoader {
|
||||
private String musicOnActivate;
|
||||
private String musicOnComplete;
|
||||
private String musicOnFailure;
|
||||
private boolean createWaypoint;
|
||||
private String planetName;
|
||||
private double locationX;
|
||||
private double locationY;
|
||||
private double locationZ;
|
||||
private String waypointName;
|
||||
private double radius;
|
||||
|
||||
private QuestTaskInfo() {
|
||||
nextTasksOnComplete = new ArrayList<>();
|
||||
@@ -571,6 +616,62 @@ public class QuestLoader extends DataLoader {
|
||||
this.musicOnFailure = musicOnFailure;
|
||||
}
|
||||
|
||||
public boolean isCreateWaypoint() {
|
||||
return createWaypoint;
|
||||
}
|
||||
|
||||
public void setCreateWaypoint(boolean createWaypoint) {
|
||||
this.createWaypoint = createWaypoint;
|
||||
}
|
||||
|
||||
public String getPlanetName() {
|
||||
return planetName;
|
||||
}
|
||||
|
||||
public void setPlanetName(String planetName) {
|
||||
this.planetName = planetName;
|
||||
}
|
||||
|
||||
public double getLocationX() {
|
||||
return locationX;
|
||||
}
|
||||
|
||||
public void setLocationX(double locationX) {
|
||||
this.locationX = locationX;
|
||||
}
|
||||
|
||||
public double getLocationY() {
|
||||
return locationY;
|
||||
}
|
||||
|
||||
public void setLocationY(double locationY) {
|
||||
this.locationY = locationY;
|
||||
}
|
||||
|
||||
public double getLocationZ() {
|
||||
return locationZ;
|
||||
}
|
||||
|
||||
public void setLocationZ(double locationZ) {
|
||||
this.locationZ = locationZ;
|
||||
}
|
||||
|
||||
public String getWaypointName() {
|
||||
return waypointName;
|
||||
}
|
||||
|
||||
public void setWaypointName(String waypointName) {
|
||||
this.waypointName = waypointName;
|
||||
}
|
||||
|
||||
public double getRadius() {
|
||||
return radius;
|
||||
}
|
||||
|
||||
public void setRadius(double radius) {
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "QuestTaskInfo{" + "index=" + index + ", type='" + type + '\'' + ", name='" + name + '\'' + '}';
|
||||
|
||||
+66
-7
@@ -1,5 +1,5 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2023 /// Project SWG /// www.projectswg.com *
|
||||
* Copyright (c) 2024 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
@@ -30,6 +30,9 @@ import com.projectswg.common.data.CRC
|
||||
import com.projectswg.common.data.encodables.oob.OutOfBandPackage
|
||||
import com.projectswg.common.data.encodables.oob.ProsePackage
|
||||
import com.projectswg.common.data.encodables.oob.StringId
|
||||
import com.projectswg.common.data.encodables.oob.waypoint.WaypointColor
|
||||
import com.projectswg.common.data.location.Location
|
||||
import com.projectswg.common.data.location.Terrain
|
||||
import com.projectswg.common.data.swgfile.ClientFactory
|
||||
import com.projectswg.common.network.packets.swg.zone.CommPlayerMessage
|
||||
import com.projectswg.common.network.packets.swg.zone.PlayMusicMessage
|
||||
@@ -44,7 +47,10 @@ import com.projectswg.holocore.intents.gameplay.player.quest.CompleteQuestIntent
|
||||
import com.projectswg.holocore.intents.gameplay.player.quest.GrantQuestIntent
|
||||
import com.projectswg.holocore.intents.gameplay.player.quest.GrantQuestIntent.Companion.broadcast
|
||||
import com.projectswg.holocore.intents.support.global.chat.SystemMessageIntent
|
||||
import com.projectswg.holocore.intents.support.global.zone.PlayerTransformedIntent
|
||||
import com.projectswg.holocore.intents.support.objects.swg.DestroyObjectIntent
|
||||
import com.projectswg.holocore.intents.support.objects.swg.ObjectCreatedIntent
|
||||
import com.projectswg.holocore.intents.support.objects.swg.ObjectTeleportIntent
|
||||
import com.projectswg.holocore.resources.support.data.server_info.StandardLog
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.QuestLoader.QuestTaskInfo
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.ServerData
|
||||
@@ -56,6 +62,7 @@ import com.projectswg.holocore.resources.support.objects.StaticItemCreator.creat
|
||||
import com.projectswg.holocore.resources.support.objects.swg.SWGObject
|
||||
import com.projectswg.holocore.resources.support.objects.swg.custom.AIObject
|
||||
import com.projectswg.holocore.resources.support.objects.swg.player.PlayerObject
|
||||
import com.projectswg.holocore.resources.support.objects.swg.waypoint.WaypointObject
|
||||
import com.projectswg.holocore.resources.support.random.Die
|
||||
import com.projectswg.holocore.resources.support.random.RandomDie
|
||||
import me.joshlarson.jlcommon.concurrency.ScheduledThreadPool
|
||||
@@ -126,12 +133,9 @@ class QuestService(private val destroyMultiAndLootDie: Die = RandomDie()) : Serv
|
||||
val killer = intent.killer
|
||||
val owner = killer.owner ?: return
|
||||
val playerObject = killer.playerObject
|
||||
val entries = playerObject.quests.entries
|
||||
for ((key, quest) in entries) {
|
||||
if (quest.isComplete) {
|
||||
continue
|
||||
}
|
||||
val questName = key.string
|
||||
val incompleteQuests = playerObject.quests.entries.filter { !it.value.isComplete }.map { it.key }
|
||||
for (incompleteQuest in incompleteQuests) {
|
||||
val questName = incompleteQuest.string
|
||||
val activeTaskListInfos = getActiveTaskInfos(questName, playerObject)
|
||||
for (activeTaskListInfo in activeTaskListInfos) {
|
||||
val type = activeTaskListInfo.type
|
||||
@@ -142,6 +146,44 @@ class QuestService(private val destroyMultiAndLootDie: Die = RandomDie()) : Serv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@IntentHandler
|
||||
private fun handlePlayerTransformedIntent(intent: PlayerTransformedIntent) {
|
||||
val player = intent.player.ownerShallow ?: return
|
||||
handlePlayerChangeLocation(player, intent.newLocation)
|
||||
}
|
||||
|
||||
@IntentHandler
|
||||
private fun handleObjectTeleportIntent(intent: ObjectTeleportIntent) {
|
||||
val player = intent.`object`.ownerShallow ?: return
|
||||
handlePlayerChangeLocation(player, intent.newLocation)
|
||||
}
|
||||
|
||||
private fun handlePlayerChangeLocation(player: Player, newLocation: Location) {
|
||||
val playerObject = player.playerObject
|
||||
val incompleteQuests = playerObject.quests.entries.filter { !it.value.isComplete }.map { it.key }
|
||||
for (incompleteQuest in incompleteQuests) {
|
||||
val questName = incompleteQuest.string
|
||||
val activeTaskListInfos = getActiveTaskInfos(questName, playerObject)
|
||||
for (activeTaskListInfo in activeTaskListInfos) {
|
||||
val type = activeTaskListInfo.type
|
||||
if (type == "quest.task.ground.go_to_location") {
|
||||
val terrain = Terrain.getTerrainFromName(activeTaskListInfo.planetName)
|
||||
val radius = activeTaskListInfo.radius
|
||||
|
||||
if (newLocation.isWithinDistance(terrain, activeTaskListInfo.locationX, activeTaskListInfo.locationY, activeTaskListInfo.locationZ, radius)) {
|
||||
StandardLog.onPlayerTrace(this, player, "arrived at location for task %d of quest %s", activeTaskListInfo.index, questName)
|
||||
completeTask(questName, player, activeTaskListInfo)
|
||||
player.sendPacket(PlayMusicMessage(0, "sound/ui_objective_reached.snd", 1, false))
|
||||
playerObject.waypoints.values.find { it.name == activeTaskListInfo.waypointName }?.let { // if you bothered with renaming the waypoint, you get to keep it
|
||||
playerObject.removeWaypoint(it.objectId)
|
||||
DestroyObjectIntent(it).broadcast()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleKillDestroyMultiAndLoot(activeTaskListInfo: QuestTaskInfo, questName: String, owner: Player, corpse: AIObject) {
|
||||
if (!isKillPartOfTask(activeTaskListInfo, corpse)) {
|
||||
@@ -297,9 +339,26 @@ class QuestService(private val destroyMultiAndLootDie: Die = RandomDie()) : Serv
|
||||
"quest.task.ground.destroy_multi_and_loot" -> handleDestroyMultiAndLoot(player, questName, currentTask)
|
||||
"quest.task.ground.reward" -> handleReward(player, questName, playerObject, currentTask)
|
||||
"quest.task.ground.nothing" -> handleNothing(player, questName, currentTask)
|
||||
"quest.task.ground.go_to_location" -> handleGoToLocation(player, currentTask)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleGoToLocation(player: Player, currentTask: QuestTaskInfo) {
|
||||
if (currentTask.isCreateWaypoint) {
|
||||
createQuestWaypoint(currentTask, player)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createQuestWaypoint(currentTask: QuestTaskInfo, player: Player) {
|
||||
val waypoint = ObjectCreator.createObjectFromTemplate("object/waypoint/shared_waypoint.iff") as WaypointObject
|
||||
waypoint.setPosition(Terrain.getTerrainFromName(currentTask.planetName), currentTask.locationX, currentTask.locationY, currentTask.locationZ)
|
||||
waypoint.color = WaypointColor.YELLOW
|
||||
waypoint.name = currentTask.waypointName
|
||||
waypoint.isActive = true
|
||||
player.playerObject.addWaypoint(waypoint)
|
||||
ObjectCreatedIntent(waypoint).broadcast()
|
||||
}
|
||||
|
||||
private fun completeTask(questName: String, player: Player, currentTask: QuestTaskInfo) {
|
||||
val playerObject = player.getPlayerObject()
|
||||
playerObject.removeActiveQuestTask(questName, currentTask.index)
|
||||
|
||||
+21
-1
@@ -1,5 +1,5 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2023 /// Project SWG /// www.projectswg.com *
|
||||
* Copyright (c) 2024 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
@@ -27,6 +27,8 @@
|
||||
package com.projectswg.holocore.services.gameplay.player.quest
|
||||
|
||||
import com.projectswg.common.data.location.Location
|
||||
import com.projectswg.common.data.location.Location.LocationBuilder
|
||||
import com.projectswg.common.data.location.Terrain
|
||||
import com.projectswg.common.network.packets.swg.login.creation.ClientCreateCharacter
|
||||
import com.projectswg.common.network.packets.swg.zone.CommPlayerMessage
|
||||
import com.projectswg.common.network.packets.swg.zone.object_controller.quest.QuestCompletedMessage
|
||||
@@ -206,6 +208,24 @@ class QuestTaskTypeTest : TestRunnerSynchronousIntents() {
|
||||
assertNotNull(questTaskTimerData, "Quest task time should have been sent")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("quest.task.ground.go_to_location")
|
||||
fun goToLocation() {
|
||||
val player = createPlayer()
|
||||
|
||||
GrantQuestIntent.broadcast(player, "quest/test_go_to_location")
|
||||
val desiredLocation = LocationBuilder()
|
||||
.setTerrain(Terrain.TATOOINE)
|
||||
.setX(-1200.0)
|
||||
.setY(0.0)
|
||||
.setZ(-3600.0)
|
||||
.build()
|
||||
player.creatureObject.moveToLocation(desiredLocation)
|
||||
val questCompletedMessage = player.waitForNextPacket(QuestCompletedMessage::class.java)
|
||||
|
||||
assertNotNull(questCompletedMessage, "Quest not completed in time")
|
||||
}
|
||||
|
||||
private class CharacterSnapshot(private val player: GenericPlayer) { // Helper class to snapshot a character's state
|
||||
val xp = player.playerObject.getExperiencePoints("dance")
|
||||
val rebelFactionPoints = player.playerObject.getFactionPoints()["rebel"] ?: 0
|
||||
|
||||
Reference in New Issue
Block a user