Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2fa9030682 | |||
| 6961b186a9 | |||
| bee91a6aa7 | |||
| 8c5b1d56c2 | |||
| f21e8c130b | |||
| 345c451ac8 |
@@ -207,7 +207,7 @@ public enum DevCmdManager {
|
||||
case "printskills":
|
||||
case "printpowers":
|
||||
case "printbonuses":
|
||||
case "gimme":
|
||||
//case "gimme":
|
||||
playerAllowed = true;
|
||||
if (!a.status.equals(Enum.AccountStatus.ADMIN))
|
||||
target = pcSender;
|
||||
|
||||
@@ -3,6 +3,8 @@ package engine.mobileAI.Threads;
|
||||
import engine.gameManager.ConfigManager;
|
||||
import engine.mobileAI.MobAI;
|
||||
import engine.gameManager.ZoneManager;
|
||||
import engine.mobileAI.behaviours.GuardAI;
|
||||
import engine.mobileAI.behaviours.SiegeEngineAI;
|
||||
import engine.objects.Mob;
|
||||
import engine.objects.Zone;
|
||||
import engine.server.MBServerStatics;
|
||||
@@ -33,6 +35,13 @@ public class MobAIThread implements Runnable{
|
||||
for (Mob mob : zone.zoneMobSet) {
|
||||
try {
|
||||
if (mob != null) {
|
||||
if(mob.isSiege()){
|
||||
SiegeEngineAI.run(mob);
|
||||
continue;
|
||||
}else if(mob.isPlayerGuard){
|
||||
GuardAI.run(mob);
|
||||
continue;
|
||||
}
|
||||
MobAI.DetermineAction(mob);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
package engine.mobileAI.behaviours;
|
||||
|
||||
import engine.Enum;
|
||||
import engine.gameManager.MovementManager;
|
||||
import engine.gameManager.PowersManager;
|
||||
import engine.gameManager.ZoneManager;
|
||||
import engine.math.Vector3f;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mobileAI.utilities.CombatUtilities;
|
||||
import engine.mobileAI.utilities.MovementUtilities;
|
||||
import engine.objects.*;
|
||||
import engine.powers.MobPowerEntry;
|
||||
import engine.powers.PowersBase;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class GuardAI {
|
||||
|
||||
public static HashMap<Mob,PowersBase> quedPowerCasts = new HashMap<>();
|
||||
|
||||
public static void run(Mob guard){
|
||||
|
||||
//1. check for players nearby to aggro to
|
||||
if(guard.combatTarget == null)
|
||||
CheckForPlayerGuardAggro(guard);
|
||||
|
||||
//2. patrol if no target acquired
|
||||
if(guard.combatTarget == null) {
|
||||
patrol(guard);
|
||||
return;
|
||||
}
|
||||
|
||||
//3. attack based on whether spellcaster, archer or mele
|
||||
if(guard.mobPowers.isEmpty()){
|
||||
if(guard.getEquip().get(2) != null && guard.getEquip().get(2).getItemBase().getRange() > 20) {
|
||||
runArcher(guard);
|
||||
}else {
|
||||
runMele(guard);
|
||||
}
|
||||
}else{
|
||||
runCaster(guard);
|
||||
}
|
||||
}
|
||||
|
||||
public static void runCaster(Mob guard){
|
||||
|
||||
}
|
||||
|
||||
public static void runMele(Mob guard){
|
||||
|
||||
}
|
||||
|
||||
public static void runArcher(Mob guard){
|
||||
|
||||
}
|
||||
|
||||
public static void CheckForPlayerGuardAggro(Mob mob) {
|
||||
|
||||
try {
|
||||
|
||||
//looks for and sets mobs combatTarget
|
||||
|
||||
if (!mob.isAlive())
|
||||
return;
|
||||
|
||||
ConcurrentHashMap<Integer, Boolean> loadedPlayers = mob.playerAgroMap;
|
||||
|
||||
for (Map.Entry playerEntry : loadedPlayers.entrySet()) {
|
||||
|
||||
int playerID = (int) playerEntry.getKey();
|
||||
PlayerCharacter loadedPlayer = PlayerCharacter.getFromCache(playerID);
|
||||
|
||||
//Player is null, let's remove them from the list.
|
||||
|
||||
if (loadedPlayer == null) {
|
||||
loadedPlayers.remove(playerID);
|
||||
continue;
|
||||
}
|
||||
|
||||
//Player is Dead, Mob no longer needs to attempt to aggro. Remove them from aggro map.
|
||||
|
||||
if (!loadedPlayer.isAlive()) {
|
||||
loadedPlayers.remove(playerID);
|
||||
continue;
|
||||
}
|
||||
|
||||
//Can't see target, skip aggro.
|
||||
|
||||
if (!mob.canSee(loadedPlayer))
|
||||
continue;
|
||||
|
||||
// No aggro for this player
|
||||
|
||||
if (GuardCanAggro(mob, loadedPlayer) == false)
|
||||
continue;
|
||||
|
||||
if (MovementUtilities.inRangeToAggro(mob, loadedPlayer) && mob.getCombatTarget() == null) {
|
||||
mob.setCombatTarget(loadedPlayer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForPlayerGuardAggro" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static Boolean GuardCanAggro(Mob mob, PlayerCharacter target) {
|
||||
|
||||
try {
|
||||
|
||||
if (mob.getGuild().getNation().equals(target.getGuild().getNation()))
|
||||
return false;
|
||||
|
||||
if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardMinion.ordinal()) {
|
||||
if (((Mob) mob.npcOwner).building.getCity().cityOutlaws.contains(target.getObjectUUID()) == true) {
|
||||
return true;
|
||||
}
|
||||
} else if (mob.building.getCity().cityOutlaws.contains(target.getObjectUUID()) == true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//first check condemn list for aggro allowed (allies button is checked)
|
||||
|
||||
if (ZoneManager.getCityAtLocation(mob.getLoc()).getTOL().reverseKOS) {
|
||||
for (Map.Entry<Integer, Condemned> entry : ZoneManager.getCityAtLocation(mob.getLoc()).getTOL().getCondemned().entrySet()) {
|
||||
|
||||
//target is listed individually
|
||||
|
||||
if (entry.getValue().getPlayerUID() == target.getObjectUUID() && entry.getValue().isActive())
|
||||
return false;
|
||||
|
||||
//target's guild is listed
|
||||
|
||||
if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild())
|
||||
return false;
|
||||
|
||||
//target's nation is listed
|
||||
|
||||
if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild().getNation())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
||||
//allies button is not checked
|
||||
|
||||
for (Map.Entry<Integer, Condemned> entry : ZoneManager.getCityAtLocation(mob.getLoc()).getTOL().getCondemned().entrySet()) {
|
||||
|
||||
//target is listed individually
|
||||
|
||||
if (entry.getValue().getPlayerUID() == target.getObjectUUID() && entry.getValue().isActive())
|
||||
return true;
|
||||
|
||||
//target's guild is listed
|
||||
|
||||
if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild())
|
||||
return true;
|
||||
|
||||
//target's nation is listed
|
||||
|
||||
if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild().getNation())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardCanAggro" + " " + e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void randomGuardPatrolPoint(Mob mob) {
|
||||
|
||||
try {
|
||||
|
||||
//early exit for a mob who is already moving to a patrol point
|
||||
//while mob moving, update lastPatrolTime so that when they stop moving the 10 second timer can begin
|
||||
|
||||
if (mob.isMoving() == true) {
|
||||
mob.stopPatrolTime = System.currentTimeMillis();
|
||||
return;
|
||||
}
|
||||
|
||||
//wait between 10 and 15 seconds after reaching patrol point before moving
|
||||
|
||||
int patrolDelay = ThreadLocalRandom.current().nextInt(10000) + 5000;
|
||||
|
||||
//early exit while waiting to patrol again
|
||||
|
||||
if (mob.stopPatrolTime + patrolDelay > System.currentTimeMillis())
|
||||
return;
|
||||
|
||||
float xPoint = ThreadLocalRandom.current().nextInt(400) - 200;
|
||||
float zPoint = ThreadLocalRandom.current().nextInt(400) - 200;
|
||||
Vector3fImmutable TreePos = mob.getGuild().getOwnedCity().getLoc();
|
||||
mob.destination = new Vector3fImmutable(TreePos.x + xPoint, TreePos.y, TreePos.z + zPoint);
|
||||
|
||||
MovementUtilities.aiMove(mob, mob.destination, true);
|
||||
|
||||
if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) {
|
||||
for (Map.Entry<Mob, Integer> minion : mob.siegeMinionMap.entrySet()) {
|
||||
|
||||
//make sure mob is out of combat stance
|
||||
|
||||
if (minion.getKey().despawned == false) {
|
||||
if (MovementUtilities.canMove(minion.getKey())) {
|
||||
Vector3f minionOffset = Formation.getOffset(2, minion.getValue() + 3);
|
||||
minion.getKey().updateLocation();
|
||||
Vector3fImmutable formationPatrolPoint = new Vector3fImmutable(mob.destination.x + minionOffset.x, mob.destination.y, mob.destination.z + minionOffset.z);
|
||||
MovementUtilities.aiMove(minion.getKey(), formationPatrolPoint, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: randomGuardPatrolPoints" + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void patrol(Mob guard){
|
||||
if (!guard.BehaviourType.equals(Enum.MobBehaviourType.GuardCaptain) && guard.npcOwner.isAlive())
|
||||
return;
|
||||
|
||||
//patrol
|
||||
Building barracks = guard.building;
|
||||
|
||||
if (barracks != null && barracks.patrolPoints != null && !barracks.getPatrolPoints().isEmpty()) {
|
||||
guard.patrolPoints = barracks.patrolPoints;
|
||||
} else {
|
||||
randomGuardPatrolPoint(guard);
|
||||
return;
|
||||
}
|
||||
if (guard.lastPatrolPointIndex > guard.patrolPoints.size() - 1)
|
||||
guard.lastPatrolPointIndex = 0;
|
||||
|
||||
guard.destination = guard.patrolPoints.get(guard.lastPatrolPointIndex);
|
||||
guard.lastPatrolPointIndex += 1;
|
||||
|
||||
MovementUtilities.aiMove(guard, guard.destination, true);
|
||||
|
||||
if (guard.BehaviourType.equals(Enum.MobBehaviourType.GuardCaptain)) {
|
||||
for (Map.Entry<Mob, Integer> minion : guard.siegeMinionMap.entrySet())
|
||||
|
||||
//make sure mob is out of combat stance
|
||||
|
||||
if (!minion.getKey().despawned) {
|
||||
if (MovementUtilities.canMove(minion.getKey())) {
|
||||
Vector3f minionOffset = Formation.getOffset(2, minion.getValue() + 3);
|
||||
minion.getKey().updateLocation();
|
||||
Vector3fImmutable formationPatrolPoint = new Vector3fImmutable(guard.destination.x + minionOffset.x, guard.destination.y, guard.destination.z + minionOffset.z);
|
||||
MovementUtilities.aiMove(minion.getKey(), formationPatrolPoint, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package engine.mobileAI.behaviours;
|
||||
|
||||
import engine.objects.Mob;
|
||||
|
||||
public class PetAI {
|
||||
|
||||
public static void run(Mob pet){
|
||||
|
||||
//1. check for combat
|
||||
|
||||
//2. check for distance from player
|
||||
|
||||
//3. follow player
|
||||
|
||||
//4. chase combat target
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package engine.mobileAI.behaviours;
|
||||
|
||||
import engine.Enum;
|
||||
import engine.gameManager.BuildingManager;
|
||||
import engine.gameManager.CombatManager;
|
||||
import engine.gameManager.MovementManager;
|
||||
import engine.gameManager.ZoneManager;
|
||||
import engine.mobileAI.utilities.CombatUtilities;
|
||||
import engine.objects.Building;
|
||||
import engine.objects.City;
|
||||
import engine.objects.Mob;
|
||||
import engine.server.MBServerStatics;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
public class SiegeEngineAI {
|
||||
|
||||
public static void run(Mob engine) {
|
||||
|
||||
//1. check to respawn if engine is dead or initially spawning
|
||||
if (!engine.isAlive() || engine.despawned) {
|
||||
if (System.currentTimeMillis() - engine.deathTime > MBServerStatics.FIFTEEN_MINUTES) {
|
||||
engine.respawn();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//2. early exit if owner is null, siege engines cannot act with player intervention
|
||||
if (engine.getOwner() == null)
|
||||
return;
|
||||
|
||||
//3. early exit if target is null, siege engines have no purpose without a target
|
||||
if (engine.combatTarget == null)
|
||||
return;
|
||||
|
||||
//4. early exit if target is not a building, siege engines can only attack buildings
|
||||
if (!engine.combatTarget.getObjectType().equals(Enum.GameObjectType.Building)) {
|
||||
engine.setCombatTarget(null);
|
||||
return;
|
||||
}
|
||||
|
||||
//5. early exit if target is out of range, engines don't move and neither do buildings, avoid infinite loop
|
||||
if(CombatManager.NotInRange(engine,engine.combatTarget,engine.getRange())) {
|
||||
engine.setCombatTarget(null);
|
||||
return;
|
||||
}
|
||||
|
||||
//6. attack target, sanity checks passed, attack target
|
||||
AttackBuilding(engine,(Building) engine.combatTarget);
|
||||
}
|
||||
|
||||
public static void AttackBuilding(Mob engine, Building target) {
|
||||
|
||||
try {
|
||||
|
||||
if (engine == null || target == null)
|
||||
return;
|
||||
|
||||
if (target.getRank() == -1 || !target.isVulnerable() || BuildingManager.getBuildingFromCache(target.getObjectUUID()) == null) {
|
||||
engine.setCombatTarget(null);
|
||||
return;
|
||||
}
|
||||
|
||||
City playercity = ZoneManager.getCityAtLocation(engine.getLoc());
|
||||
|
||||
if (playercity != null)
|
||||
for (Mob guard : playercity.getParent().zoneMobSet)
|
||||
if (guard.BehaviourType != null && guard.BehaviourType.equals(Enum.MobBehaviourType.GuardCaptain))
|
||||
if (guard.getCombatTarget() == null && guard.getGuild() != null && engine.getGuild() != null && !guard.getGuild().equals(engine.getGuild()))
|
||||
guard.setCombatTarget(engine);
|
||||
|
||||
|
||||
MovementManager.sendRWSSMsg(engine);
|
||||
|
||||
CombatUtilities.combatCycle(engine, target, true, null);
|
||||
int delay = 15000;
|
||||
engine.setLastAttackTime(System.currentTimeMillis() + delay);
|
||||
|
||||
|
||||
//if (mob.isSiege()) {
|
||||
// PowerProjectileMsg ppm = new PowerProjectileMsg(mob, target);
|
||||
// ppm.setRange(50);
|
||||
// DispatchMessage.dispatchMsgToInterestArea(mob, ppm, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
|
||||
//}
|
||||
|
||||
} catch (Exception e) {
|
||||
Logger.info(engine.getObjectUUID() + " " + engine.getName() + " Failed At: AttackBuilding" + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package engine.mobileAI.behaviours;
|
||||
|
||||
import engine.objects.Mob;
|
||||
|
||||
public class StandardAI {
|
||||
public static void run(Mob mob){
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -395,8 +395,14 @@ public class City extends AbstractWorldObject {
|
||||
//open city, just list
|
||||
if (city.open && city.getTOL() != null && city.getTOL().getRank() > 4) {
|
||||
cities.add(city);
|
||||
}else if(city.getGuild().getNation().equals(pc.guild.getNation())){
|
||||
cities.add(city);
|
||||
}else {
|
||||
try {
|
||||
if (city.getGuild().getNation().equals(pc.guild.getNation())) {
|
||||
cities.add(city);
|
||||
}
|
||||
}catch(Exception e){
|
||||
Logger.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (city.isNpc == 1) {
|
||||
|
||||
@@ -409,7 +409,6 @@ public class Experience {
|
||||
|
||||
grantedExperience = (double) LOOTMANAGER.NORMAL_EXP_RATE * maxXPPerKill(playerCharacter.getLevel());
|
||||
|
||||
grantedExperience *= (1/ giveEXPTo.size()+0.9);
|
||||
// Adjust XP for Mob Level
|
||||
|
||||
grantedExperience *= getConMod(playerCharacter, mob);
|
||||
@@ -446,6 +445,9 @@ public class Experience {
|
||||
if (grantedExperience == 0)
|
||||
grantedExperience = 1;
|
||||
|
||||
//scaling
|
||||
grantedExperience *= (1 / giveEXPTo.size()+0.9);
|
||||
|
||||
// Grant the player the EXP
|
||||
playerCharacter.grantXP((int) Math.floor(grantedExperience));
|
||||
}
|
||||
@@ -469,9 +471,13 @@ public class Experience {
|
||||
grantedExperience *= LOOTMANAGER.HOTZONE_EXP_RATE;
|
||||
|
||||
// Errant penalty
|
||||
if (grantedExperience != 1)
|
||||
if (grantedExperience != 1) {
|
||||
if (killer.getGuild().isEmptyGuild())
|
||||
grantedExperience *= .6;
|
||||
grantedExperience *= 0.6f;
|
||||
}
|
||||
|
||||
//bonus for no group
|
||||
grantedExperience *= 1.9f;
|
||||
|
||||
// Grant XP
|
||||
killer.grantXP((int) Math.floor(grantedExperience));
|
||||
|
||||
@@ -5147,6 +5147,26 @@ public class PlayerCharacter extends AbstractCharacter {
|
||||
forceRespawn(this);
|
||||
return;
|
||||
}
|
||||
if(!this.timestamps.containsKey("stamTick")){
|
||||
this.timestamps.put("stamTick", System.currentTimeMillis());
|
||||
}else{
|
||||
if(this.containsEffect(441156479) || this.containsEffect(441156455)) {
|
||||
if(System.currentTimeMillis() - this.timestamps.get("stamTick") > 5000){
|
||||
boolean worked = false;
|
||||
while(!worked) {
|
||||
float old = this.stamina.get();
|
||||
float mod = old + 4;
|
||||
if (mod > this.staminaMax)
|
||||
mod = this.staminaMax;
|
||||
|
||||
worked = this.stamina.compareAndSet(old, mod);
|
||||
}
|
||||
this.timestamps.put("stamTick", System.currentTimeMillis());
|
||||
}
|
||||
}else{
|
||||
this.timestamps.put("stamTick", System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isAlive() && this.isActive && this.enteredWorld) {
|
||||
|
||||
@@ -5885,16 +5905,10 @@ public class PlayerCharacter extends AbstractCharacter {
|
||||
// Reset this char's frame time.
|
||||
this.lastUpdateTime = System.currentTimeMillis();
|
||||
this.lastStamUpdateTime = System.currentTimeMillis();
|
||||
//this.updateMovementState();
|
||||
///boolean updateHealth = this.regenerateHealth();
|
||||
//boolean updateMana = this.regenerateMana();
|
||||
//boolean updateStamina = this.regenerateStamina();
|
||||
//boolean consumeStamina = this.consumeStamina();
|
||||
|
||||
if (this.timestamps.get("SyncClient") + 5000L < System.currentTimeMillis()) {
|
||||
//if (updateHealth || updateMana || updateStamina || consumeStamina) {
|
||||
this.syncClient();
|
||||
this.timestamps.put("SyncClient", System.currentTimeMillis());
|
||||
//}
|
||||
this.syncClient();
|
||||
this.timestamps.put("SyncClient", System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user