Merge pull request #1283 from madsboddum/Holocore-1275

[Mission] Terminal missions spawn lairs
This commit is contained in:
Josh
2023-04-15 12:44:09 -05:00
committed by GitHub
4 changed files with 85 additions and 41 deletions
@@ -1,5 +1,5 @@
/***********************************************************************************
* Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
* Copyright (c) 2023 /// 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. *
@@ -53,14 +53,27 @@ import me.joshlarson.jlcommon.control.IntentChain;
import me.joshlarson.jlcommon.log.Log;
import me.joshlarson.jlcommon.utilities.Arguments;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
public class NPCCreator {
public static AIObject createNPC(Spawner spawner) {
public static Collection<AIObject> createNPCs(Spawner spawner) {
Arguments.validate(spawner.getMinLevel() <= spawner.getMaxLevel(), "min level must be less than max level");
int amount = spawner.getAmount();
Collection<AIObject> npcs = new ArrayList<>();
for (int i = 0; i < amount; i++) {
npcs.add(createNPC(spawner));
}
return npcs;
}
private static AIObject createNPC(Spawner spawner) {
int combatLevel = ThreadLocalRandom.current().nextInt(spawner.getMinLevel(), spawner.getMaxLevel()+1);
AIObject object = ObjectCreator.createObjectFromTemplate(spawner.getRandomIffTemplate(), AIObject.class);
@@ -31,6 +31,7 @@ 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.encodables.oob.waypoint.WaypointPackage
import com.projectswg.common.data.encodables.tangible.PvpFlag
import com.projectswg.common.data.location.Location
import com.projectswg.common.data.location.Terrain
import com.projectswg.common.data.swgfile.ClientFactory
@@ -38,7 +39,6 @@ import com.projectswg.common.network.packets.swg.zone.object_controller.MissionA
import com.projectswg.common.network.packets.swg.zone.object_controller.MissionAcceptRequest
import com.projectswg.common.network.packets.swg.zone.object_controller.MissionAcceptResponse
import com.projectswg.common.network.packets.swg.zone.object_controller.MissionListRequest
import com.projectswg.holocore.intents.gameplay.combat.CreatureKilledIntent
import com.projectswg.holocore.intents.support.global.chat.SystemMessageIntent
import com.projectswg.holocore.intents.support.global.network.InboundPacketIntent
import com.projectswg.holocore.intents.support.objects.swg.DestroyObjectIntent
@@ -58,9 +58,11 @@ import com.projectswg.holocore.resources.support.objects.swg.SWGObject
import com.projectswg.holocore.resources.support.objects.swg.ServerAttribute
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureDifficulty
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject
import com.projectswg.holocore.resources.support.objects.swg.custom.AIObject
import com.projectswg.holocore.resources.support.objects.swg.custom.AIBehavior
import com.projectswg.holocore.resources.support.objects.swg.group.GroupObject
import com.projectswg.holocore.resources.support.objects.swg.mission.MissionObject
import com.projectswg.holocore.resources.support.objects.swg.tangible.OptionFlag
import com.projectswg.holocore.resources.support.objects.swg.tangible.TangibleObject
import com.projectswg.holocore.resources.support.objects.swg.waypoint.WaypointObject
import com.projectswg.holocore.services.support.objects.ObjectStorageService.ObjectLookup
import me.joshlarson.jlcommon.control.IntentHandler
@@ -74,7 +76,7 @@ class DestroyMissionService : Service() {
private val maxAcceptedMissions = 2
private val missionsToGenerate = 5
private val npcToMission = mutableMapOf<AIObject, MissionObject>()
private val lairToMission = mutableMapOf<TangibleObject, MissionObject>()
private val missionComplete = StringId("mission/mission_generic", "success_w_amount")
@IntentHandler
@@ -107,11 +109,9 @@ class DestroyMissionService : Service() {
return
}
npcToMission.filterValues { it == missionObject }.forEach {
val key = it.key
DestroyObjectIntent.broadcast(key)
DestroyObjectIntent.broadcast(npcToMission.remove(key))
}
val lairs = lairToMission.filterValues { it == missionObject }.keys
lairs.forEach { lairToMission.remove(it) }
DestroyObjectIntent.broadcast(missionObject)
val response = MissionAbort(creatureObject.objectId)
response.missionObjectId = missionObjectId
@@ -119,13 +119,13 @@ class DestroyMissionService : Service() {
}
@IntentHandler
private fun handleCreatureKilled(creatureKilledIntent: CreatureKilledIntent) {
val corpse = creatureKilledIntent.corpse
val missionObject = npcToMission.remove(corpse)
private fun handleDestroyObject(destroyObjectIntent: DestroyObjectIntent) {
val destroyedObject = destroyObjectIntent.`object`
val missionObject = lairToMission.remove(destroyedObject)
if (missionObject != null) {
val owner = missionObject.owner
if (owner != null) {
handleMissionCompleted(owner, missionObject, corpse.location)
handleMissionCompleted(owner, missionObject, destroyedObject.location)
}
}
}
@@ -188,12 +188,14 @@ class DestroyMissionService : Service() {
val location = missionObject.startLocation.toLocation()
missionObject.waypointPackage = createWaypoint(location)
spawnNpc(location, missionObject)
val lair = createLair(missionObject, location)
lairToMission[lair] = missionObject
spawnNpcs(location, missionObject)
StandardLog.onPlayerEvent(this, player, "accepted %s", missionObject)
}
}
private fun spawnNpc(location: Location, missionObject: MissionObject) {
private fun spawnNpcs(location: Location, missionObject: MissionObject) {
val difficulty = missionObject.difficulty
val egg = ObjectCreator.createObjectFromTemplate(SpawnerType.MISSION_EASY.objectTemplate)
egg.containerPermissions = AdminPermissions.getPermissions()
@@ -213,10 +215,20 @@ class DestroyMissionService : Service() {
.withMinLevel(difficulty)
.withMaxLevel(difficulty)
.withLocation(location)
.withAmount(3)
.withBehavior(AIBehavior.LOITER)
.build()
val npc = NPCCreator.createNPC(Spawner(spawnInfo, egg))
npcToMission[npc] = missionObject
NPCCreator.createNPCs(Spawner(spawnInfo, egg))
}
private fun createLair(missionObject: MissionObject, location: Location): TangibleObject {
val lair = ObjectCreator.createObjectFromTemplate(missionObject.targetAppearance.string) as TangibleObject
lair.removeOptionFlags(OptionFlag.INVULNERABLE)
lair.setPvpFlags(PvpFlag.YOU_CAN_ATTACK)
lair.moveToContainer(null, location)
ObjectCreatedIntent.broadcast(lair)
return lair
}
private fun handleTooManyMissions(creatureObject: CreatureObject, missionId: Long, missionAcceptRequest: MissionAcceptRequest, player: Player) {
@@ -1,29 +1,29 @@
/***********************************************************************************
* Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
* *
* Copyright (c) 2023 /// 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. *
* Our goal is to create an emulator which will provide a server for players to *
* continue playing a game similar to the one they used to play. We are basing *
* it on the final publish of the game prior to end-game events. *
* *
* *
* This file is part of Holocore. *
* *
* *
* --------------------------------------------------------------------------------*
* *
* *
* Holocore is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* *
* Holocore is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with Holocore. If not, see <http:></http:>//www.gnu.org/licenses/>. *
*/
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
***********************************************************************************/
package com.projectswg.holocore.services.support.npc.spawn
import com.projectswg.common.data.location.Location
@@ -153,7 +153,9 @@ class SpawnerService : Service() {
val respawnDelay = spawner.respawnDelay
if (respawnDelay > 0) {
executor.execute((respawnDelay * 1000).toLong()) { respawn(spawner) }
executor.execute((respawnDelay * 1000).toLong()) {
NPCCreator.createNPCs(spawner)
}
} else {
DestroyObjectIntent.broadcast(spawner.egg)
}
@@ -199,10 +201,8 @@ class SpawnerService : Service() {
val egg = createEgg(spawn)
val spawner = Spawner(spawn, egg)
egg.setServerAttribute(ServerAttribute.EGG_SPAWNER, spawner)
for (i in 0 until spawner.amount) {
NPCCreator.createNPC(spawner)
}
NPCCreator.createNPCs(spawner)
val patrolRoute = spawner.patrolRoute
if (patrolRoute != null) {
@@ -217,13 +217,7 @@ class SpawnerService : Service() {
}
}
}
private fun respawn(spawner: Spawner) {
for (i in spawner.npcs.size until spawner.amount) {
NPCCreator.createNPC(spawner)
}
}
private fun createEgg(spawn: SpawnInfo): SWGObject {
val spawnerType = SpawnerType.valueOf(spawn.spawnerType)
val egg = ObjectCreator.createObjectFromTemplate(spawnerType.objectTemplate)
@@ -1,3 +1,29 @@
/***********************************************************************************
* Copyright (c) 2023 /// 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. *
* Our goal is to create an emulator which will provide a server for players to *
* continue playing a game similar to the one they used to play. We are basing *
* it on the final publish of the game prior to end-game events. *
* *
* This file is part of Holocore. *
* *
* --------------------------------------------------------------------------------*
* *
* Holocore is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* Holocore is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
***********************************************************************************/
package com.projectswg.holocore.services.gameplay.combat
import com.projectswg.common.data.location.Location
@@ -8,7 +34,6 @@ import com.projectswg.holocore.resources.support.npc.spawn.Spawner
import com.projectswg.holocore.resources.support.objects.ObjectCreator
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureDifficulty
import com.projectswg.holocore.resources.support.objects.swg.custom.AIObject
import com.projectswg.holocore.resources.support.objects.swg.weapon.WeaponObject
import com.projectswg.holocore.test.runners.TestRunnerSynchronousIntents
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
@@ -55,7 +80,7 @@ class NpcDefaultAttackTest : TestRunnerSynchronousIntents() {
.withLocation(inFrontOfMosEisleyStarport)
.build()
return NPCCreator.createNPC(Spawner(spawnInfo, egg))
return NPCCreator.createNPCs(Spawner(spawnInfo, egg)).first()
}
}