mirror of
https://github.com/ProjectSWGCore/Holocore.git
synced 2026-10-04 19:13:19 -04:00
Merged in M4SS/holocore/feature/gcw (pull request #545)
Galactic Civil War
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2018 /// 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.intents;
|
||||
|
||||
import com.projectswg.common.control.Intent;
|
||||
import com.projectswg.holocore.resources.objects.player.PlayerObject;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class CivilWarPointIntent extends Intent {
|
||||
|
||||
private final PlayerObject receiver;
|
||||
private final int points;
|
||||
|
||||
@Nonnull
|
||||
private CivilWarPointIntent(PlayerObject receiver, int points) {
|
||||
this.receiver = receiver;
|
||||
this.points = points;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public PlayerObject getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
public int getPoints() {
|
||||
return points;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static void broadcast(PlayerObject receiver, int points) {
|
||||
new CivilWarPointIntent(receiver, points).broadcast();
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -32,6 +32,8 @@ import com.projectswg.common.data.location.Terrain;
|
||||
import com.projectswg.common.data.sui.SuiEvent;
|
||||
import com.projectswg.common.debug.Log;
|
||||
|
||||
import com.projectswg.holocore.intents.CivilWarPointIntent;
|
||||
import com.projectswg.holocore.resources.objects.player.PlayerObject;
|
||||
import com.projectswg.holocore.scripts.commands.admin.qatool.QaToolDetails;
|
||||
import com.projectswg.holocore.intents.chat.SystemMessageIntent;
|
||||
import com.projectswg.holocore.intents.experience.ExperienceIntent;
|
||||
@@ -102,6 +104,9 @@ public class QaToolCmdCallback implements ICmdCallback {
|
||||
else
|
||||
SystemMessageIntent.broadcastPersonal(player, "QATool XP: Expected format: /qatool xp <xpType> <xpGained>");
|
||||
break;
|
||||
case "gcw":
|
||||
grantGcw(player, command[1]);
|
||||
break;
|
||||
default:
|
||||
displayMainWindow(player);
|
||||
break;
|
||||
@@ -226,6 +231,19 @@ public class QaToolCmdCallback implements ICmdCallback {
|
||||
}
|
||||
}
|
||||
|
||||
private void grantGcw(Player player, String pointsArg) {
|
||||
PlayerObject receiver = player.getCreatureObject().getPlayerObject();
|
||||
|
||||
try {
|
||||
int points = Integer.parseInt(pointsArg);
|
||||
CivilWarPointIntent.broadcast(receiver, points);
|
||||
Log.i("GCW command: %s gave themselves %d GCW points", player.getUsername(), points);
|
||||
} catch (NumberFormatException e) {
|
||||
SystemMessageIntent.broadcastPersonal(player, String.format("GCW command: %s is not a number", pointsArg));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Utility Methods */
|
||||
|
||||
private void createMessageBox(Player player, String title, String prompt) {
|
||||
|
||||
@@ -0,0 +1,406 @@
|
||||
/************************************************************************************
|
||||
* Copyright (c) 2015 /// 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.faction;
|
||||
|
||||
import com.projectswg.common.concurrency.PswgScheduledThreadPool;
|
||||
import com.projectswg.common.control.Service;
|
||||
import com.projectswg.common.data.encodables.oob.ProsePackage;
|
||||
import com.projectswg.common.data.encodables.oob.StringId;
|
||||
import com.projectswg.common.data.encodables.tangible.PvpFaction;
|
||||
import com.projectswg.common.data.encodables.tangible.PvpStatus;
|
||||
import com.projectswg.common.debug.Log;
|
||||
import com.projectswg.common.network.packets.swg.zone.PlayClientEffectObjectMessage;
|
||||
import com.projectswg.common.network.packets.swg.zone.PlayMusicMessage;
|
||||
import com.projectswg.holocore.intents.CivilWarPointIntent;
|
||||
import com.projectswg.holocore.intents.chat.SystemMessageIntent;
|
||||
import com.projectswg.holocore.intents.combat.CreatureKilledIntent;
|
||||
import com.projectswg.holocore.intents.object.DestroyObjectIntent;
|
||||
import com.projectswg.holocore.intents.object.ObjectCreatedIntent;
|
||||
import com.projectswg.holocore.resources.objects.SWGObject;
|
||||
import com.projectswg.holocore.resources.objects.creature.CreatureDifficulty;
|
||||
import com.projectswg.holocore.resources.objects.creature.CreatureObject;
|
||||
import com.projectswg.holocore.resources.objects.player.PlayerObject;
|
||||
import com.projectswg.holocore.resources.server_info.SdbLoader;
|
||||
import com.projectswg.holocore.resources.server_info.StandardLog;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
final class CivilWarService extends Service {
|
||||
|
||||
private static final int IMPERIAL_INDEX = 0;
|
||||
private static final int REBEL_INDEX = 1;
|
||||
|
||||
private final Map<Integer, String[]> rankAbilities;
|
||||
private final Set<PlayerObject> playerObjects;
|
||||
private final PswgScheduledThreadPool threadPool;
|
||||
private final DayOfWeek updateWeekDay;
|
||||
private final LocalTime updateTime;
|
||||
private final ZoneOffset updateOffset;
|
||||
private int rankEpoch;
|
||||
|
||||
CivilWarService() {
|
||||
rankAbilities = new HashMap<>();
|
||||
playerObjects = ConcurrentHashMap.newKeySet();
|
||||
threadPool = new PswgScheduledThreadPool(1, "civil-war-service");
|
||||
// Rank update time is the night between Thursday and Friday at 00:00 UTC
|
||||
updateWeekDay = DayOfWeek.FRIDAY;
|
||||
updateTime = LocalTime.MIDNIGHT;
|
||||
updateOffset = ZoneOffset.UTC;
|
||||
|
||||
loadRankAbilities();
|
||||
|
||||
registerForIntent(CivilWarPointIntent.class, this::handleCivilWarPointIntent);
|
||||
registerForIntent(CreatureKilledIntent.class, this::handleCreatureKilledIntent);
|
||||
registerForIntent(DestroyObjectIntent.class, this::handleDestroyObjectIntent);
|
||||
registerForIntent(ObjectCreatedIntent.class, this::handleObjectCreatedIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean initialize() {
|
||||
threadPool.start();
|
||||
scheduleRankUpdate();
|
||||
|
||||
return super.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean terminate() {
|
||||
threadPool.stop(); // To stop more threads from running
|
||||
threadPool.awaitTermination(1000); // Waits for them to complete executing
|
||||
|
||||
return super.terminate();
|
||||
}
|
||||
|
||||
int leftoverPoints(float progress, int points) {
|
||||
return (int) ((progress - 100) / 100 * (float) points);
|
||||
}
|
||||
|
||||
boolean isRankDown(float oldProgress, float newProgress) {
|
||||
return oldProgress + newProgress < 0;
|
||||
}
|
||||
|
||||
int nextUpdateTime(LocalDate now) {
|
||||
LocalDate nextUpdateDate = now.with(updateWeekDay);
|
||||
|
||||
return (int) nextUpdateDate.toEpochSecond(updateTime, updateOffset);
|
||||
}
|
||||
|
||||
boolean isDecayRank(int rank) {
|
||||
return rank >= 7; // Lieutenant and above has decay
|
||||
}
|
||||
|
||||
float rankProgress(float currentProgress, float decay, int currentRank, int points) {
|
||||
float progress = currentProgress - decay;
|
||||
|
||||
progress += (float) points / (currentRank * 100.0f);
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
boolean isFactionEligible(PvpFaction killerFaction, PvpFaction corpseFaction, boolean specialForces) {
|
||||
return killerFaction != PvpFaction.NEUTRAL && corpseFaction != PvpFaction.NEUTRAL && killerFaction != corpseFaction && specialForces;
|
||||
}
|
||||
|
||||
byte makeMultiplier(boolean specialForces, boolean player) {
|
||||
byte multiplier = 1;
|
||||
|
||||
if (specialForces) {
|
||||
multiplier += 1;
|
||||
}
|
||||
|
||||
if (player) {
|
||||
multiplier += 18;
|
||||
}
|
||||
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
int baseForDifficulty(CreatureDifficulty difficulty) {
|
||||
switch (difficulty) {
|
||||
case NORMAL:
|
||||
return 5;
|
||||
case ELITE:
|
||||
return 10;
|
||||
case BOSS:
|
||||
return 15;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unhandled CreatureDifficulty: " + difficulty);
|
||||
}
|
||||
}
|
||||
|
||||
int pointsGranted(int base, byte multiplier) {
|
||||
return base * multiplier;
|
||||
}
|
||||
|
||||
private void loadRankAbilities() {
|
||||
String what = "rank abilities";
|
||||
long startTime = StandardLog.onStartLoad(what);
|
||||
|
||||
try (SdbLoader.SdbResultSet set = SdbLoader.load(new File("serverdata/gcw/abilities.sdb"))) {
|
||||
while (set.next()) {
|
||||
int rank = (int) set.getInt("rank");
|
||||
String imperial = set.getText("imperial");
|
||||
String rebel = set.getText("rebel");
|
||||
String[] abilities = new String[2];
|
||||
|
||||
abilities[IMPERIAL_INDEX] = imperial;
|
||||
abilities[REBEL_INDEX] = rebel;
|
||||
|
||||
rankAbilities.put(rank, abilities);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
|
||||
StandardLog.onEndLoad(rankAbilities.size(), what, startTime);
|
||||
}
|
||||
|
||||
private void scheduleRankUpdate() {
|
||||
LocalDate now = LocalDate.now();
|
||||
int nowEpoch = (int) now.toEpochSecond(updateTime, updateOffset);
|
||||
rankEpoch = nextUpdateTime(now); // Is in the future
|
||||
int delay = (rankEpoch - nowEpoch) * 1000; // Must be milliseconds
|
||||
|
||||
threadPool.execute(delay, this::updateRanks);
|
||||
playerObjects.forEach(this::updateTimer);
|
||||
}
|
||||
|
||||
private void updateTimer(PlayerObject playerObject) {
|
||||
playerObject.setGcwNextUpdate(rankEpoch);
|
||||
}
|
||||
|
||||
private void changeRank(PlayerObject playerObject, int newRank) {
|
||||
assert (newRank < 1 || newRank > 12);
|
||||
|
||||
int oldRank = playerObject.getCurrentRank();
|
||||
|
||||
assert (oldRank > 1);
|
||||
|
||||
int highestRank = Math.max(oldRank, newRank);
|
||||
int lowestRank = Math.min(oldRank, newRank);
|
||||
CreatureObject creature = (CreatureObject) playerObject.getParent();
|
||||
PvpFaction faction = creature.getPvpFaction();
|
||||
int abilityIndex = faction == PvpFaction.IMPERIAL ? IMPERIAL_INDEX : REBEL_INDEX;
|
||||
|
||||
playerObject.setCurrentRank(newRank);
|
||||
|
||||
if (oldRank > newRank) {
|
||||
// They've been demoted
|
||||
for (int rank = highestRank; rank >= lowestRank; rank--) {
|
||||
if (!isDecayRank(rank)) {
|
||||
break;
|
||||
}
|
||||
|
||||
String ability = rankAbilities.get(rank)[abilityIndex];
|
||||
|
||||
creature.removeAbility(ability);
|
||||
}
|
||||
} else if (oldRank < newRank) {
|
||||
// They've been promoted
|
||||
for (int rank = lowestRank; rank <= highestRank; rank++) {
|
||||
if (!isDecayRank(rank)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String ability = rankAbilities.get(rank)[abilityIndex];
|
||||
|
||||
creature.addAbility(ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateRank(PlayerObject playerObject) {
|
||||
int currentRank = playerObject.getCurrentRank();
|
||||
float oldProgress = playerObject.getRankProgress();
|
||||
int points = playerObject.getGcwPoints();
|
||||
float decay = 0;
|
||||
|
||||
if (isDecayRank(currentRank)) {
|
||||
decay = currentRank;
|
||||
}
|
||||
|
||||
float newProgress = rankProgress(oldProgress, decay, currentRank, points);
|
||||
|
||||
if (newProgress >= 100) {
|
||||
int promotion = playerObject.getCurrentRank() + 1;
|
||||
|
||||
changeRank(playerObject, promotion);
|
||||
|
||||
// Leftover points carry over
|
||||
int leftoverPoints = leftoverPoints(newProgress, points);
|
||||
|
||||
// Calculate progress within the new rank using leftover points
|
||||
float nextRankProgress = rankProgress(newProgress, 0, promotion, leftoverPoints);
|
||||
|
||||
playerObject.setRankProgress(nextRankProgress);
|
||||
} else if (newProgress > 0) {
|
||||
// Set their new progress
|
||||
playerObject.setRankProgress(newProgress);
|
||||
} else if (newProgress < 0 && isRankDown(oldProgress, newProgress)) {
|
||||
int demotion = playerObject.getCurrentRank() - 1;
|
||||
|
||||
changeRank(playerObject, demotion);
|
||||
|
||||
// Push their progress backwards in the new rank
|
||||
int leftoverPoints = leftoverPoints(newProgress, points);
|
||||
|
||||
// Calculate progress within the new rank using leftover points
|
||||
float nextRankProgress = 100 - rankProgress(newProgress, 0, demotion, leftoverPoints);
|
||||
|
||||
playerObject.setRankProgress(nextRankProgress);
|
||||
}
|
||||
|
||||
int kills = playerObject.getPvpKills();
|
||||
|
||||
// Reset current kills and points
|
||||
playerObject.setGcwPoints(0);
|
||||
playerObject.setPvpKills(0);
|
||||
|
||||
// Add current stats to lifetime stats
|
||||
playerObject.setLifetimeGcwPoints(playerObject.getLifetimeGcwPoints() + points);
|
||||
playerObject.setLifetimePvpKills(playerObject.getLifetimePvpKills() + kills);
|
||||
|
||||
// TODO award GCW abilities
|
||||
}
|
||||
|
||||
private void updateRanks() {
|
||||
playerObjects.forEach(playerObject -> {
|
||||
if (playerObject.getCurrentRank() > 0)
|
||||
updateRank(playerObject);
|
||||
});
|
||||
|
||||
scheduleRankUpdate(); // Schedule next rank update
|
||||
}
|
||||
|
||||
private void grantPoints(ProsePackage prose, PlayerObject receiver, int points) {
|
||||
receiver.setGcwPoints(receiver.getGcwPoints() + points);
|
||||
SystemMessageIntent.broadcastPersonal(receiver.getOwner(), prose);
|
||||
}
|
||||
|
||||
private void handleCivilWarPointIntent(CivilWarPointIntent cwpi) {
|
||||
int points = cwpi.getPoints();
|
||||
PlayerObject receiver = cwpi.getReceiver();
|
||||
ProsePackage prose = new ProsePackage(new StringId("gcw", "gcw_rank_generic_point_grant"), "DI", points);
|
||||
|
||||
grantPoints(prose, receiver, points);
|
||||
}
|
||||
|
||||
private void handleCreatureKilledIntent(CreatureKilledIntent cki) {
|
||||
CreatureObject corpseCreature = cki.getCorpse();
|
||||
CreatureObject killerCreature = cki.getKiller();
|
||||
PvpFaction killerFaction = killerCreature.getPvpFaction();
|
||||
|
||||
if (!killerCreature.isPlayer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean specialForces = corpseCreature.getPvpStatus() == PvpStatus.SPECIALFORCES;
|
||||
|
||||
if (!isFactionEligible(killerFaction, corpseCreature.getPvpFaction(), specialForces)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerObject killerPlayer = killerCreature.getPlayerObject();
|
||||
|
||||
byte multiplier = makeMultiplier(specialForces, corpseCreature.isPlayer());
|
||||
int base = baseForDifficulty(corpseCreature.getDifficulty());
|
||||
int granted = pointsGranted(base, multiplier);
|
||||
ProsePackage prose;
|
||||
|
||||
if (specialForces) {
|
||||
// Increment kill counter
|
||||
killerPlayer.setPvpKills(killerPlayer.getPvpKills() + 1);
|
||||
|
||||
// Determine which effect and sound to play
|
||||
String effectFile;
|
||||
String soundFile;
|
||||
|
||||
if (killerFaction == PvpFaction.REBEL) {
|
||||
effectFile = "clienteffect/holoemote_rebel.cef";
|
||||
soundFile = "sound/music_themequest_victory_rebel.snd";
|
||||
} else {
|
||||
effectFile = "clienteffect/holoemote_imperial.cef";
|
||||
soundFile = "sound/music_themequest_victory_imperial.snd";
|
||||
}
|
||||
|
||||
// PvP GCW point system message
|
||||
prose = new ProsePackage("StringId", new StringId("gcw", "gcw_rank_pvp_kill_point_grant"), "DI", granted, "TT", corpseCreature
|
||||
.getObjectName());
|
||||
|
||||
// Send visual effect to killer and everyone around
|
||||
killerCreature.sendObserversAndSelf(new PlayClientEffectObjectMessage(effectFile, "head", killerCreature.getObjectId(), ""));
|
||||
|
||||
// Send sound to just to the killer
|
||||
killerCreature.sendSelf(new PlayMusicMessage(0, soundFile, 0, false));
|
||||
|
||||
// TODO planetary control points?
|
||||
} else {
|
||||
// NPC GCW point system message
|
||||
prose = new ProsePackage(new StringId("gcw", "gcw_rank_generic_point_grant"), "DI", granted);
|
||||
}
|
||||
|
||||
// Increment GCW point counter
|
||||
grantPoints(prose, killerPlayer, granted);
|
||||
}
|
||||
|
||||
private void handleDestroyObjectIntent(DestroyObjectIntent doi) {
|
||||
SWGObject object = doi.getObject();
|
||||
|
||||
if (!(object instanceof PlayerObject)) {
|
||||
return;
|
||||
}
|
||||
|
||||
playerObjects.remove(object);
|
||||
}
|
||||
|
||||
private void handleObjectCreatedIntent(ObjectCreatedIntent oci) {
|
||||
SWGObject object = oci.getObject();
|
||||
|
||||
if (!(object instanceof PlayerObject)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerObject playerObject = (PlayerObject) object;
|
||||
|
||||
// Let's make sure the timer's displayed for them
|
||||
updateTimer(playerObject);
|
||||
|
||||
playerObjects.add(playerObject);
|
||||
}
|
||||
|
||||
}
|
||||
+12
-4
@@ -32,7 +32,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import com.projectswg.common.concurrency.PswgScheduledThreadPool;
|
||||
import com.projectswg.common.control.Service;
|
||||
import com.projectswg.common.control.Manager;
|
||||
import com.projectswg.common.data.encodables.tangible.PvpFaction;
|
||||
import com.projectswg.common.data.encodables.tangible.PvpFlag;
|
||||
import com.projectswg.common.data.encodables.tangible.PvpStatus;
|
||||
@@ -45,15 +45,17 @@ import com.projectswg.holocore.resources.objects.creature.CreatureObject;
|
||||
import com.projectswg.holocore.resources.objects.tangible.TangibleObject;
|
||||
import com.projectswg.holocore.resources.player.Player;
|
||||
|
||||
public final class FactionService extends Service {
|
||||
public final class FactionManager extends Manager {
|
||||
|
||||
private final Map<TangibleObject, Future<?>> statusChangers;
|
||||
private final PswgScheduledThreadPool executor;
|
||||
|
||||
public FactionService() {
|
||||
public FactionManager() {
|
||||
statusChangers = new ConcurrentHashMap<>();
|
||||
executor = new PswgScheduledThreadPool(1, "faction-service");
|
||||
|
||||
addChildService(new CivilWarService());
|
||||
|
||||
registerForIntent(FactionIntent.class, this::handleFactionIntent);
|
||||
}
|
||||
|
||||
@@ -97,7 +99,13 @@ public final class FactionService extends Service {
|
||||
|
||||
if(target.getBaselineType() == BaselineType.CREO && target.getPvpFaction() != PvpFaction.NEUTRAL) {
|
||||
// We're given rank 1 upon joining a non-neutral faction
|
||||
((CreatureObject) target).setFactionRank((byte) 1);
|
||||
CreatureObject creatureTarget = (CreatureObject) target;
|
||||
|
||||
if (!creatureTarget.isPlayer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
creatureTarget.getPlayerObject().setCurrentRank(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import com.projectswg.holocore.services.commands.CommandService;
|
||||
import com.projectswg.holocore.services.commands.EntertainmentService;
|
||||
import com.projectswg.holocore.services.crafting.CraftingManager;
|
||||
import com.projectswg.holocore.services.experience.ExperienceManager;
|
||||
import com.projectswg.holocore.services.faction.FactionService;
|
||||
import com.projectswg.holocore.services.faction.FactionManager;
|
||||
import com.projectswg.holocore.services.group.GroupService;
|
||||
import com.projectswg.holocore.services.sui.SuiService;
|
||||
|
||||
@@ -49,7 +49,7 @@ public class GameManager extends Manager {
|
||||
addChildService(new CollectionService());
|
||||
addChildService(new CollectionBadgeManager());
|
||||
addChildService(new EnvironmentService());
|
||||
addChildService(new FactionService());
|
||||
addChildService(new FactionManager());
|
||||
addChildService(new GroupService());
|
||||
addChildService(new SkillModService());
|
||||
addChildService(new EntertainmentService());
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
***********************************************************************************/
|
||||
package com.projectswg.holocore.services;
|
||||
|
||||
import com.projectswg.holocore.services.faction.TestCivilWarService;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
import org.junit.runners.Suite.SuiteClasses;
|
||||
@@ -38,6 +39,7 @@ import com.projectswg.holocore.services.player.TestPlayer;
|
||||
|
||||
@RunWith(Suite.class)
|
||||
@SuiteClasses({
|
||||
TestCivilWarService.class,
|
||||
TestRareLootService.class,
|
||||
TestCrafting.class,
|
||||
TestPlayer.class,
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/************************************************************************************
|
||||
* Copyright (c) 2015 /// 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.faction;
|
||||
|
||||
import com.projectswg.common.data.encodables.tangible.PvpFaction;
|
||||
import com.projectswg.holocore.resources.objects.creature.CreatureDifficulty;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class TestCivilWarService {
|
||||
|
||||
private final CivilWarService service;
|
||||
|
||||
public TestCivilWarService() {
|
||||
service = new CivilWarService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsFactionEligible() {
|
||||
Assert.assertTrue(service.isFactionEligible(PvpFaction.REBEL, PvpFaction.IMPERIAL, true));
|
||||
Assert.assertFalse(service.isFactionEligible(PvpFaction.NEUTRAL, PvpFaction.NEUTRAL, false));
|
||||
Assert.assertFalse(service.isFactionEligible(PvpFaction.NEUTRAL, PvpFaction.REBEL, false));
|
||||
Assert.assertFalse(service.isFactionEligible(PvpFaction.NEUTRAL, PvpFaction.IMPERIAL, false));
|
||||
Assert.assertFalse(service.isFactionEligible(PvpFaction.REBEL, PvpFaction.REBEL, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeMultiplier() {
|
||||
Assert.assertEquals(1, service.makeMultiplier(false, false));
|
||||
Assert.assertEquals(2, service.makeMultiplier(true, false));
|
||||
Assert.assertEquals(19, service.makeMultiplier(false, true));
|
||||
Assert.assertEquals(20, service.makeMultiplier(true, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBaseForDifficulty() {
|
||||
Assert.assertEquals(5, service.baseForDifficulty(CreatureDifficulty.NORMAL));
|
||||
Assert.assertEquals(10, service.baseForDifficulty(CreatureDifficulty.ELITE));
|
||||
Assert.assertEquals(15, service.baseForDifficulty(CreatureDifficulty.BOSS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPointsGranted() {
|
||||
Assert.assertEquals(200, service.pointsGranted(10, (byte) 20));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextUpdateTime() {
|
||||
LocalDate now = LocalDate.of(2018, 2, 19); // It's a Monday
|
||||
LocalDate rankDay = LocalDate.of(2018, 2, 23); // It's a Friday
|
||||
int expectedRankTime = 1519344000; // The Friday that week, at 00:00 UTC (night between thursday and friday)
|
||||
|
||||
Assert.assertEquals(expectedRankTime, service.nextUpdateTime(now));
|
||||
Assert.assertEquals(expectedRankTime, service.nextUpdateTime(rankDay));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsDecayRank() {
|
||||
Assert.assertFalse(service.isDecayRank(6));
|
||||
Assert.assertTrue(service.isDecayRank(7));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRankProgress() {
|
||||
Assert.assertEquals(2.86f, service.rankProgress(10.0f, 20.0f, 7, 9000), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsRankDown() {
|
||||
Assert.assertFalse(service.isRankDown(40, 50));
|
||||
Assert.assertTrue(service.isRankDown(3, -10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeftoverPoints() {
|
||||
Assert.assertEquals(6000, service.leftoverPoints(130, 20000));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user