Compare commits

...

126 Commits

Author SHA1 Message Date
FatBoy-DOTC 7e457fa17b all items form "Noob Helper" cost 2 gold 5 months ago
FatBoy-DOTC 926b9d2bae R8 ToL can have 4 shrines 5 months ago
FatBoy-DOTC c5822b5acf dropper resists and level increase 5 months ago
FatBoy-DOTC 516b66a50a reintroduce blood rune droppers on 3 hour disc cycle 5 months ago
FatBoy-DOTC 39305d63c7 noob island gear 5 months ago
FatBoy-DOTC c0cb856961 noob island gear 5 months ago
FatBoy-DOTC 2fb97a676f allow some dev commands for players (print) 5 months ago
FatBoy-DOTC cbff151dc3 allow some dev commands for players (print) 5 months ago
FatBoy-DOTC eed75fd2fd repair costs calculated properly 5 months ago
FatBoy-DOTC 6374390b34 repair cost synced with server values 5 months ago
FatBoy-DOTC 2185d3ef7c rune merchants pricing adjusts 5 months ago
FatBoy-DOTC 4aaa96e36c resourc emerchant pricing adjust 5 months ago
FatBoy-DOTC bf86680547 higher present drop chance 5 months ago
FatBoy-DOTC 960307e262 rune pricing fix 5 months ago
FatBoy-DOTC eedf96cc31 resource pricing fix 5 months ago
FatBoy-DOTC 6fb5fce4d3 fixed profit error for NPCs 5 months ago
FatBoy-DOTC 7688d21fe6 boons refreshable, boon level determined by votary rank, shrines should work for all, boons nation friendly again 5 months ago
FatBoy-DOTC 23e60b36b4 General Cleanup and drop rates 5 months ago
FatBoy-DOTC ab8fc8e0a0 random vorg droppers, max durability repairable 5 months ago
FatBoy-DOTC b30f04046d uniform disc dropper times 5 months ago
FatBoy-DOTC 9bd03c7d43 pricing corrected for rune vendors 5 months ago
FatBoy-DOTC 78118a1ac1 fix for rune application 5 months ago
FatBoy-DOTC 1f863d0cce resource pricing fix 5 months ago
FatBoy-DOTC c49204aeeb NPC have 0 maint, fix for resource merchant 5 months ago
FatBoy-DOTC b1de3755fd display correct maintenance costs 5 months ago
FatBoy-DOTC 83a1cc5aba maintenance display on buildings 5 months ago
FatBoy-DOTC 9b0b15c31e remove refund for deranked building due to maintenance 5 months ago
FatBoy-DOTC 802651d2d4 rune application error fixed 5 months ago
FatBoy-DOTC 52a48e5618 rune application checks 5 months ago
FatBoy-DOTC 14fe248e19 mine serializing 5 months ago
FatBoy-DOTC 5b81be371e mine serializing 5 months ago
FatBoy-DOTC 82d67f2850 mine serializing 5 months ago
FatBoy-DOTC 1c342bd566 server pop on creation displays amount of realms captured 5 months ago
FatBoy-DOTC bb8ad3c971 character creation population message 5 months ago
FatBoy-DOTC e9fef85b72 set maintenance dates correctly 5 months ago
FatBoy-DOTC c0d1a4f274 mines produce once a day, maintenance system for TOL only 5 months ago
FatBoy-DOTC 94be3335a0 mine production change error tracking 5 months ago
FatBoy-DOTC 7d03f78546 rune application require/restrict actually use values 5 months ago
FatBoy-DOTC 023f933d0b rune application require/restrict actually use values 5 months ago
FatBoy-DOTC 9995cc01b7 rune application require/restrict actually use values 5 months ago
FatBoy-DOTC fd03b263d1 pets follow owners through teleporting 5 months ago
FatBoy-DOTC 6a09a3fd44 pets follow owners through teleporting 5 months ago
FatBoy-DOTC 1322f8610c safe guards dont kill pets anymore 5 months ago
FatBoy-DOTC 90ab6175b5 extra ToL slots 5 months ago
FatBoy-DOTC 2e3e9ee882 extra ToL slots 5 months ago
FatBoy-DOTC 5158329785 Saetor can take Chaos Shrine boon 5 months ago
FatBoy-DOTC b8e0165da2 allowed siege engineer alchemist and banker on ToL 5 months ago
FatBoy-DOTC 0fa6ebc136 fix pets 5 months ago
FatBoy-DOTC 4e5e362197 attempt to fix mine serialization 5 months ago
FatBoy-DOTC 61514fef2b attempt to fix mine serialization 5 months ago
FatBoy-DOTC 59e593ab0d attempt to fix mine serialization 5 months ago
FatBoy-DOTC 2c6ea98ef9 revert instant respawns 5 months ago
FatBoy-DOTC bd3ea16b57 faster respawns 5 months ago
FatBoy-DOTC 45165332f6 faster respawns 5 months ago
FatBoy-DOTC d764a66e55 logging 5 months ago
FatBoy-DOTC ac41e64429 logging 5 months ago
FatBoy-DOTC 462beb30b3 logging 5 months ago
FatBoy-DOTC 3a89e9c087 logging 5 months ago
FatBoy-DOTC e71863cbd2 logging 5 months ago
FatBoy-DOTC 5ec0ff0598 logging 5 months ago
FatBoy-DOTC 2ca9b77cfb logging 5 months ago
FatBoy-DOTC 4f535ef5fe loot manager for glass runes and contracts 5 months ago
FatBoy-DOTC a46ad71bb0 loot manager for glass runes and contracts 5 months ago
FatBoy-DOTC 90d6911d41 loot manager for glass runes and contracts 5 months ago
FatBoy-DOTC e13ebae0df loot manager for glass runes and contracts 5 months ago
FatBoy-DOTC 3e15fc8206 bootysim command work 5 months ago
FatBoy-DOTC 6a400467dd drop rate work 5 months ago
FatBoy-DOTC 488188e9c3 glass chance work 5 months ago
FatBoy-DOTC 0d31bc4280 contract and rune drop work 5 months ago
FatBoy-DOTC 6375b4431c box check 5 months ago
FatBoy-DOTC 683422f8a4 auto identify all items 5 months ago
FatBoy-DOTC e4dbad2669 generic loot system in place 5 months ago
FatBoy-DOTC 34721fdee8 generic loot system in place 5 months ago
FatBoy-DOTC f27668552c corrected pricing for +10 runes 5 months ago
FatBoy-DOTC 306fdf4235 permanent open runegates 5 months ago
FatBoy-DOTC 553b09d827 rune pricing corrected 5 months ago
FatBoy-DOTC 8ee17f0c64 fix resource merchant elan stones pricing 5 months ago
FatBoy-DOTC 7e5ad644d3 fix resource merchant elan stones 5 months ago
FatBoy-DOTC 846b8a7cde fix resource merchant margins 5 months ago
FatBoy-DOTC f27a4f174b error popup when trying to flag unboxed too frequently 5 months ago
FatBoy-DOTC c6d4375aa8 error popup when trying to flag unboxed too frequently 5 months ago
FatBoy-DOTC b9ec54c76a enrollment office removes DS effect 5 months ago
FatBoy-DOTC b351d7c1ae enrollment officer system 5 months ago
FatBoy-DOTC 729ebe7cd0 box checker 5 months ago
FatBoy-DOTC f51c28e708 revert boxing enforcement 5 months ago
FatBoy-DOTC 9fbf55127d sourcetype lookup fix 5 months ago
FatBoy-DOTC f9fd61dc6b revert sourcetype lookup fix 5 months ago
FatBoy-DOTC 4f198e1f53 Merge remote-tracking branch 'origin/lakebane-new' into lakebane-new 5 months ago
FatBoy-DOTC 24c85a5140 revert sourcetype lookup fix 5 months ago
FatBoy-DOTC 3e1a5f4ccd SpurceType lookup fixes for Piercing Crushing and Slashing 5 months ago
FatBoy-DOTC 34e5a3878c SpurceType lookup fixes for Piercing Crushing and Slashing 5 months ago
FatBoy-DOTC 663e285091 Deathshroud applied ot all boxed characters 5 months ago
FatBoy-DOTC d87c03bb79 fixed combat message to reflect proper zerg multiplier values 5 months ago
FatBoy-DOTC abc57688d3 reset zerg multipliers when window closes 5 months ago
FatBoy-DOTC 29671d56fc display zerg multiplier in ./info 5 months ago
FatBoy-DOTC e8cf6a722b remove hotzone form the game 5 months ago
FatBoy-DOTC 2793ec331b mines revert to claimable at 1am CST 5 months ago
FatBoy-DOTC 1a0b91b068 buying larger stacks of resources form resource vendor 5 months ago
FatBoy-DOTC bec6cbe6e6 implement stat modifications for the ZergMultiplier 5 months ago
FatBoy-DOTC f7ab10ff07 altered mine production values 5 months ago
FatBoy-DOTC 9671cbdc1a unlimited sub guilds 5 months ago
FatBoy-DOTC e0af1f5932 no caps on claimable mines for nations 5 months ago
FatBoy-DOTC 8cb52c6142 zerg multiplier resets for players after mine closes 5 months ago
FatBoy-DOTC e5133211a9 Zerg Mechanic for Mines 5 months ago
FatBoy-DOTC 8548612a80 items auto ID 5 months ago
FatBoy-DOTC 41c3193275 irekei movespeed fix 5 months ago
FatBoy-DOTC 15771d2802 new characters start at level 10 5 months ago
FatBoy-DOTC b4a62e5f3e update inventory when junking for gold 5 months ago
FatBoy-DOTC fc7e6735a1 mine tower health scales with cap size 5 months ago
FatBoy-DOTC aeb21c328e max slots for rank adjustments 5 months ago
FatBoy-DOTC 9a34b13c2e junk from inventory 5 months ago
FatBoy-DOTC 231feef7fe mines open during a reboot time frame now open correctly 5 months ago
FatBoy-DOTC 0e6b68139f refactor mine processing to HalfHourlyJob 5 months ago
FatBoy-DOTC ef62c2bb39 mines open and close 5 months ago
FatBoy-DOTC 8f68997f3c terraform size correction 5 months ago
FatBoy-DOTC aebe2698c3 terraform size correction 5 months ago
FatBoy-DOTC 54e7a8fc7f display mine times correctly 5 months ago
FatBoy-DOTC 8b4d37c53c fix for mines loading 5 months ago
FatBoy-DOTC fbfca46d2f fix for mines loading 5 months ago
FatBoy-DOTC 3228f473de fix for mines loading 5 months ago
FatBoy-DOTC 17fcf0ee40 duplicated zone loading disabled 5 months ago
FatBoy-DOTC 395fe31e02 duplicated zone loading disabled 5 months ago
FatBoy-DOTC e98f9cf1f7 duplicated zone loading disabled 5 months ago
FatBoy-DOTC fe0c0f97a5 duplicated zone loading disabled 5 months ago
FatBoy-DOTC 7e27838818 mine changes 5 months ago
FatBoy-DOTC bc8094c20c saetor race as minotaurs 5 months ago
  1. 26
      src/engine/Enum.java
  2. 3
      src/engine/InterestManagement/InterestManager.java
  3. 19
      src/engine/db/handlers/dbCityHandler.java
  4. 10
      src/engine/db/handlers/dbHandlerBase.java
  5. 14
      src/engine/db/handlers/dbItemHandler.java
  6. 45
      src/engine/devcmd/cmds/AddNPCCmd.java
  7. 77
      src/engine/devcmd/cmds/HotzoneCmd.java
  8. 3
      src/engine/devcmd/cmds/InfoCmd.java
  9. 5
      src/engine/devcmd/cmds/MineActiveCmd.java
  10. 6
      src/engine/devcmd/cmds/SimulateBootyCmd.java
  11. 25
      src/engine/gameManager/BuildingManager.java
  12. 4
      src/engine/gameManager/CombatManager.java
  13. 14
      src/engine/gameManager/DevCmdManager.java
  14. 277
      src/engine/gameManager/LootManager.java
  15. 26
      src/engine/gameManager/MaintenanceManager.java
  16. 17
      src/engine/gameManager/SimulationManager.java
  17. 92
      src/engine/gameManager/ZergManager.java
  18. 73
      src/engine/gameManager/ZoneManager.java
  19. 14
      src/engine/loot/ItemTableEntry.java
  20. 22
      src/engine/mobileAI/MobAI.java
  21. 195
      src/engine/net/client/ClientMessagePump.java
  22. 15
      src/engine/net/client/handlers/ArcMineChangeProductionMsgHandler.java
  23. 2
      src/engine/net/client/handlers/CityDataHandler.java
  24. 57
      src/engine/net/client/handlers/MerchantMsgHandler.java
  25. 20
      src/engine/net/client/handlers/ObjectActionMsgHandler.java
  26. 96
      src/engine/net/client/msg/ApplyRuneMsg.java
  27. 8
      src/engine/net/client/msg/CityDataMsg.java
  28. 6
      src/engine/net/client/msg/ManageCityAssetsMsg.java
  29. 40
      src/engine/net/client/msg/ServerInfoMsg.java
  30. 5
      src/engine/net/client/msg/VendorDialogMsg.java
  31. 33
      src/engine/objects/AbstractCharacter.java
  32. 46
      src/engine/objects/Blueprint.java
  33. 21
      src/engine/objects/Building.java
  34. 91
      src/engine/objects/Contract.java
  35. 6
      src/engine/objects/Guild.java
  36. 17
      src/engine/objects/Item.java
  37. 151
      src/engine/objects/ItemBase.java
  38. 216
      src/engine/objects/Mine.java
  39. 18
      src/engine/objects/Mob.java
  40. 4
      src/engine/objects/MobEquipment.java
  41. 2
      src/engine/objects/MobLoot.java
  42. 52
      src/engine/objects/PlayerCharacter.java
  43. 21
      src/engine/objects/Resists.java
  44. 27
      src/engine/objects/Shrine.java
  45. 78
      src/engine/objects/Warehouse.java
  46. 5
      src/engine/objects/Zone.java
  47. 22
      src/engine/server/world/WorldServer.java
  48. 166
      src/engine/workthreads/HalfHourlyJobThread.java
  49. 257
      src/engine/workthreads/HourlyJobThread.java

26
src/engine/Enum.java

@ -139,8 +139,8 @@ public class Enum {
HALFGIANTMALE(2010, MonsterType.HalfGiant, RunSpeed.STANDARD, CharacterSex.MALE, 1.15f), HALFGIANTMALE(2010, MonsterType.HalfGiant, RunSpeed.STANDARD, CharacterSex.MALE, 1.15f),
HUMANMALE(2011, MonsterType.Human, RunSpeed.STANDARD, CharacterSex.MALE, 1), HUMANMALE(2011, MonsterType.Human, RunSpeed.STANDARD, CharacterSex.MALE, 1),
HUMANFEMALE(2012, MonsterType.Human, RunSpeed.STANDARD, CharacterSex.FEMALE, 1), HUMANFEMALE(2012, MonsterType.Human, RunSpeed.STANDARD, CharacterSex.FEMALE, 1),
IREKEIMALE(2013, MonsterType.Irekei, RunSpeed.STANDARD, CharacterSex.MALE, 1.1f), IREKEIMALE(2013, MonsterType.Irekei, RunSpeed.IREKEI, CharacterSex.MALE, 1.1f),
IREKEIFEMALE(2014, MonsterType.Irekei, RunSpeed.STANDARD, CharacterSex.FEMALE, 1.1f), IREKEIFEMALE(2014, MonsterType.Irekei, RunSpeed.IREKEI, CharacterSex.FEMALE, 1.1f),
SHADEMALE(2015, MonsterType.Shade, RunSpeed.STANDARD, CharacterSex.MALE, 1), SHADEMALE(2015, MonsterType.Shade, RunSpeed.STANDARD, CharacterSex.MALE, 1),
SHADEFEMALE(2016, MonsterType.Shade, RunSpeed.STANDARD, CharacterSex.FEMALE, 1), SHADEFEMALE(2016, MonsterType.Shade, RunSpeed.STANDARD, CharacterSex.FEMALE, 1),
MINOMALE(2017, MonsterType.Minotaur, RunSpeed.MINOTAUR, CharacterSex.MALE, 1.3f), MINOMALE(2017, MonsterType.Minotaur, RunSpeed.MINOTAUR, CharacterSex.MALE, 1.3f),
@ -172,6 +172,8 @@ public class Enum {
} }
public static RaceType getRaceTypebyRuneID(int runeID) { public static RaceType getRaceTypebyRuneID(int runeID) {
if(runeID == 1999)
return _raceTypeByID.get(2017);
return _raceTypeByID.get(runeID); return _raceTypeByID.get(runeID);
} }
@ -208,7 +210,8 @@ public class Enum {
SENTINEL(0, 0, 0, 0, 0, 0, 0), SENTINEL(0, 0, 0, 0, 0, 0, 0),
STANDARD(6.1900001f, 13.97f, 4.2199998f, 13.97f, 6.3299999f, 18.379999f, 6.5f), STANDARD(6.1900001f, 13.97f, 4.2199998f, 13.97f, 6.3299999f, 18.379999f, 6.5f),
CENTAUR(6.1900001f, 16.940001f, 5.5500002f, 16.940001f, 6.3299999f, 18.379999f, 6.5f), CENTAUR(6.1900001f, 16.940001f, 5.5500002f, 16.940001f, 6.3299999f, 18.379999f, 6.5f),
MINOTAUR(6.6300001f, 15.95f, 4.2199998f, 15.95f, 6.3299999f, 18.379999f, 6.5f); MINOTAUR(6.6300001f, 15.95f, 4.2199998f, 15.95f, 6.3299999f, 18.379999f, 6.5f),
IREKEI(6.35f, 15.25f, 4.2199998f, 14.5f, 6.3299999f, 18.379999f, 6.5f);
private float walkStandard; private float walkStandard;
private float walkCombat; private float walkCombat;
@ -957,6 +960,17 @@ public class Enum {
Wizardry; Wizardry;
public static SourceType GetSourceType(String modName) { public static SourceType GetSourceType(String modName) {
switch(modName){
case "Slashing":
modName = "Slash";
break;
case "Crushing":
modName = "Crush";
break;
case "Piercing":
modName = "Pierce";
break;
}
SourceType returnMod; SourceType returnMod;
if (modName.isEmpty()) if (modName.isEmpty())
return SourceType.None; return SourceType.None;
@ -2306,9 +2320,9 @@ public class Enum {
public enum CityBoundsType { public enum CityBoundsType {
GRID(640), GRID(544),
ZONE(875), ZONE(672),
PLACEMENT(876); PLACEMENT(673);
public final float extents; public final float extents;

3
src/engine/InterestManagement/InterestManager.java

@ -521,9 +521,12 @@ public enum InterestManager implements Runnable {
// Update loaded upbjects lists // Update loaded upbjects lists
player.isBoxed = PlayerCharacter.checkIfBoxed(player);
player.setDirtyLoad(true); player.setDirtyLoad(true);
updateStaticList(player, origin); updateStaticList(player, origin);
updateMobileList(player, origin); updateMobileList(player, origin);
if(player.level < 10)
player.setLevel((short) 10);
} }

19
src/engine/db/handlers/dbCityHandler.java

@ -95,7 +95,26 @@ public class dbCityHandler extends dbHandlerBase {
return objectList; return objectList;
} }
public Integer GET_CAPITAL_CITY_COUNT() {
int cityCount = 0;
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM obj_city;")) {
ResultSet rs = preparedStatement.executeQuery();
while(rs.next()){
if(rs.getInt("isNpc") == 0)
if(DbManager.BuildingQueries.GET_BUILDINGBYUUID(rs.getInt("treeOfLifeUUID")).getRank() == 8)
cityCount++;
}
} catch (SQLException e) {
Logger.error(e);
}
return cityCount;
}
public ArrayList<City> GET_CITIES_BY_ZONE(final int objectUUID) { public ArrayList<City> GET_CITIES_BY_ZONE(final int objectUUID) {
ArrayList<City> cityList = new ArrayList<>(); ArrayList<City> cityList = new ArrayList<>();

10
src/engine/db/handlers/dbHandlerBase.java

@ -32,7 +32,6 @@ public abstract class dbHandlerBase {
try { try {
if (rs.next()) { if (rs.next()) {
abstractGameObject = localClass.getConstructor(ResultSet.class).newInstance(rs); abstractGameObject = localClass.getConstructor(ResultSet.class).newInstance(rs);
DbManager.addToCache(abstractGameObject); DbManager.addToCache(abstractGameObject);
} }
} catch (Exception e) { } catch (Exception e) {
@ -61,8 +60,17 @@ public abstract class dbHandlerBase {
if (DbManager.inCache(localObjectType, id)) { if (DbManager.inCache(localObjectType, id)) {
objectList.add((T) DbManager.getFromCache(localObjectType, id)); objectList.add((T) DbManager.getFromCache(localObjectType, id));
} else { } else {
try{
if(rs.getInt("mineLiveHour") == 1)
continue;
}catch(Exception e){
//not a mine
}
AbstractGameObject toAdd = localClass.getConstructor(ResultSet.class).newInstance(rs); AbstractGameObject toAdd = localClass.getConstructor(ResultSet.class).newInstance(rs);
DbManager.addToCache(toAdd); DbManager.addToCache(toAdd);
if(toAdd.getObjectType().equals(GameObjectType.Zone) && rs.getInt("canLoad") == 0){
continue;
}
objectList.add((T) toAdd); objectList.add((T) toAdd);
if (toAdd != null && toAdd instanceof AbstractWorldObject) if (toAdd != null && toAdd instanceof AbstractWorldObject)

14
src/engine/db/handlers/dbItemHandler.java

@ -496,4 +496,18 @@ public class dbItemHandler extends dbHandlerBase {
return false; return false;
} }
} }
public boolean UPDATE_NUM_ITEMS(final Item item, int newValue) {
if (item.getItemBase().getType().equals(ItemType.GOLD))
return false;
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE `obj_item` SET `item_numberOfItems`=? WHERE `UID`=?")) {
preparedStatement.setInt(1, newValue);
preparedStatement.setLong(2, item.getObjectUUID());
return (preparedStatement.executeUpdate() > 0);
} catch (SQLException e) {
Logger.error(e);
return false;
}
}
} }

45
src/engine/devcmd/cmds/AddNPCCmd.java

@ -13,6 +13,7 @@ import engine.Enum.GameObjectType;
import engine.InterestManagement.WorldGrid; import engine.InterestManagement.WorldGrid;
import engine.devcmd.AbstractDevCmd; import engine.devcmd.AbstractDevCmd;
import engine.gameManager.*; import engine.gameManager.*;
import engine.math.Vector3fImmutable;
import engine.objects.*; import engine.objects.*;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@ -31,7 +32,6 @@ public class AddNPCCmd extends AbstractDevCmd {
int contractID; int contractID;
String name = ""; String name = "";
int level = 0; int level = 0;
if (words.length < 2) { if (words.length < 2) {
this.sendUsage(pc); this.sendUsage(pc);
return; return;
@ -39,59 +39,54 @@ public class AddNPCCmd extends AbstractDevCmd {
try { try {
contractID = Integer.parseInt(words[0]); contractID = Integer.parseInt(words[0]);
level = Integer.parseInt(words[1]); level = Integer.parseInt(words[1]);
for (int i = 2; i < words.length; i++) { for (int i = 2; i < words.length; i++) {
name += words[i]; name += words[i];
if (i + 1 < words.length) if (i + 1 < words.length)
name += ""; name += "";
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throwbackError(pc, throwbackError(pc,
"Failed to parse supplied contractID or level to an Integer."); "Failed to parse supplied contractID or level to an Integer.");
return; // NaN return; // NaN
} }
Contract contract = DbManager.ContractQueries.GET_CONTRACT(contractID); Contract contract = DbManager.ContractQueries.GET_CONTRACT(contractID);
if (contract == null || level < 1 || level > 75) { if (contract == null || level < 1 || level > 75) {
throwbackError(pc, throwbackError(pc,
"Invalid addNPC Command. Need contract ID, and level"); "Invalid addNPC Command. Need contract ID, and level");
return; // NaN return; // NaN
} }
// Pick a random name // Pick a random name
if (name.isEmpty()) if (name.isEmpty())
name = NPCManager.getPirateName(contract.getMobbaseID()); name = NPCManager.getPirateName(contract.getMobbaseID());
Zone zone = ZoneManager.findSmallestZone(pc.getLoc()); Zone zone = ZoneManager.findSmallestZone(pc.getLoc());
if (zone == null) { if (zone == null) {
throwbackError(pc, "Failed to find zone to place npc in."); throwbackError(pc, "Failed to find zone to place npc in.");
return; return;
} }
Building building = null;
if (target != null) if (target != null)
if (target.getObjectType() == GameObjectType.Building) { if (target.getObjectType() == GameObjectType.Building) {
Building parentBuilding = (Building) target; building = (Building)target;
BuildingManager.addHirelingForWorld(parentBuilding, pc, parentBuilding.getLoc(), parentBuilding.getParentZone(), contract, level);
return;
} }
NPC created;
NPC npc = NPC.createNPC(name, contractID, Guild guild = null;
pc.getLoc(), null, zone, (short) level, null); Vector3fImmutable loc;
if(building != null){
if (npc != null) { guild = building.getGuild();
WorldGrid.addObject(npc, pc); loc = building.loc;
ChatManager.chatSayInfo(pc,
"NPC with ID " + npc.getDBID() + " added");
this.setResult(String.valueOf(npc.getDBID()));
} else{ } else{
throwbackError(pc, "Failed to create npc of contract type " loc = pc.loc;
+ contractID); }
Logger.error( created = NPC.createNPC(name, contractID, loc, guild, zone, (short)level, building);
"Failed to create npc of contract type " + contractID); created.bindLoc = loc;
if(building != null) {
created.buildingUUID = building.getObjectUUID();
created.building = building;
NPCManager.slotCharacterInBuilding(created);
} }
created.setLoc(created.bindLoc);
created.updateDatabase();
throwbackInfo(pc, "Created NPC with UUID: " + created.getObjectUUID());
} }
@Override @Override

77
src/engine/devcmd/cmds/HotzoneCmd.java

@ -1,77 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd;
import engine.gameManager.ZoneManager;
import engine.objects.AbstractGameObject;
import engine.objects.PlayerCharacter;
/**
* ./hotzone <- display the current hotzone & time remaining
* ./hotzone random <- change hotzone to random new zone
*/
public class HotzoneCmd extends AbstractDevCmd {
public HotzoneCmd() {
super("hotzone");
}
@Override
protected void _doCmd(PlayerCharacter playerCharacter, String[] words,
AbstractGameObject target) {
StringBuilder data = new StringBuilder();
String outString;
for (String s : words) {
data.append(s);
data.append(' ');
}
String input = data.toString().trim();
if (input.length() == 0) {
outString = "Current hotZone: " + ZoneManager.hotZone.getName() + "\r\n";
outString += "Available hotZones: " + ZoneManager.availableHotZones();
throwbackInfo(playerCharacter, outString);
return;
}
if (input.equalsIgnoreCase("random")) {
ZoneManager.generateAndSetRandomHotzone();
outString = "New hotZone: " + ZoneManager.hotZone.getName() + "\r\n";
outString += "Available hotZones: " + ZoneManager.availableHotZones();
throwbackInfo(playerCharacter, outString);
return;
}
if (input.equalsIgnoreCase("reset")) {
ZoneManager.resetHotZones();
throwbackInfo(playerCharacter, "Available hotZones: " + ZoneManager.availableHotZones());
return;
}
return;
}
@Override
protected String _getHelpString() {
return "Use no arguments to see the current hotzone or \"random\" to change it randomly.";
}
@Override
protected String _getUsageString() {
return "'./hotzone [random]";
}
}

3
src/engine/devcmd/cmds/InfoCmd.java

@ -337,7 +337,8 @@ public class InfoCmd extends AbstractDevCmd {
output += "Swimming : " + targetPC.isSwimming(); output += "Swimming : " + targetPC.isSwimming();
output += newline; output += newline;
output += "isMoving : " + targetPC.isMoving(); output += "isMoving : " + targetPC.isMoving();
output += newline;
output += "Zerg Multiplier : " + targetPC.ZergMultiplier;
break; break;
case NPC: case NPC:

5
src/engine/devcmd/cmds/MineActiveCmd.java

@ -16,6 +16,7 @@ import engine.objects.AbstractGameObject;
import engine.objects.Building; import engine.objects.Building;
import engine.objects.Mine; import engine.objects.Mine;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.workthreads.HalfHourlyJobThread;
import engine.workthreads.HourlyJobThread; import engine.workthreads.HourlyJobThread;
/** /**
@ -41,10 +42,10 @@ public class MineActiveCmd extends AbstractDevCmd {
String trigger = args[0]; String trigger = args[0];
switch (trigger) { switch (trigger) {
case "true": case "true":
HourlyJobThread.mineWindowOpen(mine); HalfHourlyJobThread.mineWindowOpen(mine);
break; break;
case "false": case "false":
HourlyJobThread.mineWindowClose(mine); HalfHourlyJobThread.mineWindowClose(mine);
break; break;
default: default:
this.sendUsage(pcSender); this.sendUsage(pcSender);

6
src/engine/devcmd/cmds/SimulateBootyCmd.java

@ -10,6 +10,8 @@ import java.util.ArrayList;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
public class SimulateBootyCmd extends AbstractDevCmd { public class SimulateBootyCmd extends AbstractDevCmd {
public int simCount = 250;
public SimulateBootyCmd() { public SimulateBootyCmd() {
super("bootysim"); super("bootysim");
} }
@ -25,7 +27,7 @@ public class SimulateBootyCmd extends AbstractDevCmd {
String output; String output;
output = "Booty Simulation:" + newline; output = "Booty Simulation: Rolls:" + simCount + newline;
Mob mob = (Mob) target; Mob mob = (Mob) target;
output += "Name: " + mob.getName() + newline; output += "Name: " + mob.getName() + newline;
@ -51,7 +53,7 @@ public class SimulateBootyCmd extends AbstractDevCmd {
int failures = 0; int failures = 0;
int goldAmount = 0; int goldAmount = 0;
for (int i = 0; i < 100; ++i) { for (int i = 0; i < simCount; ++i) {
try { try {
mob.loadInventory(); mob.loadInventory();

25
src/engine/gameManager/BuildingManager.java

@ -520,7 +520,30 @@ public enum BuildingManager {
if (building.getBlueprintUUID() == 0) if (building.getBlueprintUUID() == 0)
return false; return false;
if (building.getBlueprint().getMaxSlots() == building.getHirelings().size()) if(building.getBlueprint().getBuildingGroup().equals(BuildingGroup.TOL)){
if(contract.getContractID() == 850) {
boolean hasRunemaster = false;
for (AbstractCharacter npc : building.getHirelings().keySet()) {
if (npc.getObjectType() != GameObjectType.NPC)
continue;
if(npc.contractUUID == 850)
hasRunemaster = true;
}
if(hasRunemaster)
return false;
}
}
int maxSlots = building.getBlueprint().getMaxSlots();
if(building.getBlueprint().getBuildingGroup() != null) {
maxSlots = building.getBlueprint().getSlotsForRank(building.getRank());
}
if (maxSlots == building.getHirelings().size())
return false; return false;
String pirateName = NPCManager.getPirateName(contract.getMobbaseID()); String pirateName = NPCManager.getPirateName(contract.getMobbaseID());

4
src/engine/gameManager/CombatManager.java

@ -1054,6 +1054,10 @@ public enum CombatManager {
if (eff.getPower() != null && (eff.getPower().getToken() == 429506943 || eff.getPower().getToken() == 429408639 || eff.getPower().getToken() == 429513599 || eff.getPower().getToken() == 429415295)) if (eff.getPower() != null && (eff.getPower().getToken() == 429506943 || eff.getPower().getToken() == 429408639 || eff.getPower().getToken() == 429513599 || eff.getPower().getToken() == 429415295))
swingAnimation = 0; swingAnimation = 0;
if(source != null && source.getObjectType().equals(GameObjectType.PlayerCharacter)){
damage *= ((PlayerCharacter)source).ZergMultiplier;
} // Health modifications are modified by the ZergMechanic
TargetedActionMsg cmm = new TargetedActionMsg(source, target, damage, swingAnimation); TargetedActionMsg cmm = new TargetedActionMsg(source, target, damage, swingAnimation);
DispatchMessage.sendToAllInRange(target, cmm); DispatchMessage.sendToAllInRange(target, cmm);
} }

14
src/engine/gameManager/DevCmdManager.java

@ -79,7 +79,6 @@ public enum DevCmdManager {
DevCmdManager.registerDevCmd(new AddGoldCmd()); DevCmdManager.registerDevCmd(new AddGoldCmd());
DevCmdManager.registerDevCmd(new ZoneInfoCmd()); DevCmdManager.registerDevCmd(new ZoneInfoCmd());
DevCmdManager.registerDevCmd(new DebugMeleeSyncCmd()); DevCmdManager.registerDevCmd(new DebugMeleeSyncCmd());
DevCmdManager.registerDevCmd(new HotzoneCmd());
DevCmdManager.registerDevCmd(new MineActiveCmd()); DevCmdManager.registerDevCmd(new MineActiveCmd());
// Dev // Dev
DevCmdManager.registerDevCmd(new ApplyStatModCmd()); DevCmdManager.registerDevCmd(new ApplyStatModCmd());
@ -179,8 +178,17 @@ public enum DevCmdManager {
//kill any commands not available to everyone on production server //kill any commands not available to everyone on production server
//only admin level can run dev commands on production //only admin level can run dev commands on production
boolean playerAllowed = false;
if (a.status.equals(Enum.AccountStatus.ADMIN) == false) { switch(adc.getMainCmdString()){
case "printresists":
case "printstats":
case "printskills":
case "printpowers":
if(!a.status.equals(Enum.AccountStatus.ADMIN))
target = pcSender;
break;
}
if (!playerAllowed && !a.status.equals(Enum.AccountStatus.ADMIN)) {
Logger.info("Account " + a.getUname() + "attempted to use dev command " + cmd); Logger.info("Account " + a.getUname() + "attempted to use dev command " + cmd);
return false; return false;
} }

277
src/engine/gameManager/LootManager.java

@ -17,7 +17,9 @@ import engine.objects.*;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
/** /**
@ -34,6 +36,11 @@ public enum LootManager {
public static HashMap<Integer, ArrayList<ModTableEntry>> _modTables = new HashMap<>(); public static HashMap<Integer, ArrayList<ModTableEntry>> _modTables = new HashMap<>();
public static HashMap<Integer, ArrayList<ModTypeTableEntry>> _modTypeTables = new HashMap<>(); public static HashMap<Integer, ArrayList<ModTypeTableEntry>> _modTypeTables = new HashMap<>();
public static final ArrayList<Integer> vorg_ha_uuids = new ArrayList<>(Arrays.asList(27580, 27590, 188500, 188510, 188520, 188530, 188540, 188550, 189510));
public static final ArrayList<Integer> vorg_ma_uuids = new ArrayList<>(Arrays.asList(27570,188900,188910,188920,188930,188940,188950,189500));
public static final ArrayList<Integer> vorg_la_uuids = new ArrayList<>(Arrays.asList(27550,27560,189100,189110,189120,189130,189140,189150));
public static final ArrayList<Integer> vorg_cloth_uuids = new ArrayList<>(Arrays.asList(27600,188700,188720,189550,189560));
// Drop Rates // Drop Rates
public static float NORMAL_DROP_RATE; public static float NORMAL_DROP_RATE;
@ -67,16 +74,66 @@ public enum LootManager {
} }
public static void GenerateMobLoot(Mob mob) { public static void GenerateMobLoot(Mob mob) {
//determine if mob is in hotzone //determine if mob is in hotzone
boolean inHotzone = ZoneManager.inHotZone(mob.getLoc()); boolean inHotzone = false;
//special blood rune droppers
MobLoot specialDrop = null;
switch(mob.getObjectUUID()) {
case 22595://elf 1
specialDrop = new MobLoot(mob,ItemBase.getItemBase(252134),true);
mob.setFirstName("Melandrach The Blood-Mage");
break;
case 22432: //elf 2
specialDrop = new MobLoot(mob,ItemBase.getItemBase(252135),true);
mob.setFirstName("Kyrtaar The Blood-Mage");
break;
case 22537: //elf 3
specialDrop = new MobLoot(mob,ItemBase.getItemBase(252136),true);
mob.setFirstName("Vamir The Blood-Mage");
break;
case 16387: //human 4 DONE
specialDrop = new MobLoot(mob,ItemBase.getItemBase(252129),true);
mob.setFirstName("Alatar The Blood-Mage");
break;
case 32724:// human 5 GOOD
specialDrop = new MobLoot(mob,ItemBase.getItemBase(252130),true);
mob.setFirstName("Elphaba The Blood-Mage");
break;
case 23379: //human 1 GOOD
specialDrop = new MobLoot(mob,ItemBase.getItemBase(252131),true);
mob.setFirstName("Bavmorda The Blood-Mage");
break;
case 10826: //human 2 REDO
specialDrop = new MobLoot(mob,ItemBase.getItemBase(252132),true);
mob.setFirstName("Draco The Blood-Mage");
break;
case 15929: //human 3 GOOD
specialDrop = new MobLoot(mob,ItemBase.getItemBase(252133),true);
mob.setFirstName("Atlantes The Blood-Mage");
break;
}
if(specialDrop != null) {
mob.setLevel((short) 65);
mob.setSpawnTime(10800);
mob.healthMax = (7500);
mob.setHealth(7500);
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().getName() + " has found the " + specialDrop.getName() + ". Are you tough enough to take it?");
chatMsg.setMessageType(10);
chatMsg.setChannel(Enum.ChatChannelType.SYSTEM.getChannelID());
DispatchMessage.dispatchMsgToAll(chatMsg);
mob.getCharItemManager().addItemToInventory(specialDrop);
mob.setResists(new Resists("Dropper"));
if(!Mob.discDroppers.contains(mob))
Mob.AddDiscDropper(mob);
}
//iterate the booty sets //iterate the booty sets
if (mob.getMobBase().bootySet != 0 && _bootySetMap.containsKey(mob.getMobBase().bootySet) == true) if (mob.getMobBase().bootySet != 0 && _bootySetMap.containsKey(mob.getMobBase().bootySet))
RunBootySet(_bootySetMap.get(mob.getMobBase().bootySet), mob, inHotzone); RunBootySet(_bootySetMap.get(mob.getMobBase().bootySet), mob, inHotzone);
if (mob.bootySet != 0 && _bootySetMap.containsKey(mob.bootySet) == true) if (mob.bootySet != 0 && _bootySetMap.containsKey(mob.bootySet))
RunBootySet(_bootySetMap.get(mob.bootySet), mob, inHotzone); RunBootySet(_bootySetMap.get(mob.bootySet), mob, inHotzone);
//lastly, check mobs inventory for godly or disc runes to send a server announcement //lastly, check mobs inventory for godly or disc runes to send a server announcement
@ -98,10 +155,25 @@ public enum LootManager {
private static void RunBootySet(ArrayList<BootySetEntry> entries, Mob mob, boolean inHotzone) { private static void RunBootySet(ArrayList<BootySetEntry> entries, Mob mob, boolean inHotzone) {
boolean hotzoneWasRan = false; boolean hotzoneWasRan = false;
float dropRate = 1.0f; float dropRate;
// Iterate all entries in this bootySet and process accordingly //1 in 1,000 chance to drop glass
if(ThreadLocalRandom.current().nextInt(1,1000) == 500){
int glassID = rollRandomItem(126);
ItemBase glassItem = ItemBase.getItemBase(glassID);
if(glassItem != null) {
MobLoot toAdd = new MobLoot(mob, glassItem, false);
if (toAdd != null)
mob.getCharItemManager().addItemToInventory(toAdd);
}
}
//check for special gifts 1/100 to drop present
if(ThreadLocalRandom.current().nextInt(1,25) == 15)
DropPresent(mob);
// Iterate all entries in this bootySet and process accordingly
for (BootySetEntry bse : entries) { for (BootySetEntry bse : entries) {
switch (bse.bootyType) { switch (bse.bootyType) {
case "GOLD": case "GOLD":
@ -109,7 +181,9 @@ public enum LootManager {
break; break;
case "LOOT": case "LOOT":
if (mob.getSafeZone() == false) if (mob.getSafeZone())
return; // no loot to drop in safezones
dropRate = LootManager.NORMAL_DROP_RATE; dropRate = LootManager.NORMAL_DROP_RATE;
if (inHotzone == true) if (inHotzone == true)
@ -172,13 +246,23 @@ public enum LootManager {
return null; return null;
if (ItemBase.getItemBase(itemUUID).getType().ordinal() == Enum.ItemType.RESOURCE.ordinal()) { if (ItemBase.getItemBase(itemUUID).getType().ordinal() == Enum.ItemType.RESOURCE.ordinal()) {
if(ThreadLocalRandom.current().nextInt(1,101) < 91)
return null; // cut down world drops rates of resources by 90%
int amount = ThreadLocalRandom.current().nextInt(tableRow.minSpawn, tableRow.maxSpawn + 1); int amount = ThreadLocalRandom.current().nextInt(tableRow.minSpawn, tableRow.maxSpawn + 1);
return new MobLoot(mob, ItemBase.getItemBase(itemUUID), amount, false); return new MobLoot(mob, ItemBase.getItemBase(itemUUID), amount, false);
} }
if(ItemBase.getItemBase(itemUUID).getType().equals(Enum.ItemType.RUNE)){
int randomRune = rollRandomItem(itemTableId);
if(randomRune != 0) {
itemUUID = randomRune;
}
} else if(ItemBase.getItemBase(itemUUID).getType().equals(Enum.ItemType.CONTRACT)){
int randomContract = rollRandomItem(itemTableId);
if(randomContract != 0) {
itemUUID = randomContract;
}
}
outItem = new MobLoot(mob, ItemBase.getItemBase(itemUUID), false); outItem = new MobLoot(mob, ItemBase.getItemBase(itemUUID), false);
Enum.ItemType outType = outItem.getItemBase().getType();
if(selectedRow.pModTable != 0){ if(selectedRow.pModTable != 0){
try { try {
@ -196,6 +280,12 @@ public enum LootManager {
Logger.error("Failed to GenerateSuffix for item: " + outItem.getName()); Logger.error("Failed to GenerateSuffix for item: " + outItem.getName());
} }
} }
if(outItem.getItemBase().getType().equals(Enum.ItemType.CONTRACT) || outItem.getItemBase().getType().equals(Enum.ItemType.RUNE)){
if(ThreadLocalRandom.current().nextInt(1,101) < 66)
return null; // cut down world drops rates of resources by 65%
}
return outItem; return outItem;
} }
@ -299,12 +389,7 @@ public enum LootManager {
int high = bse.highGold; int high = bse.highGold;
int low = bse.lowGold; int low = bse.lowGold;
int gold = ThreadLocalRandom.current().nextInt(low, high + 1); int gold = (int) (ThreadLocalRandom.current().nextInt(low, high + 1) * NORMAL_GOLD_RATE);
if (inHotzone == true)
gold = (int) (gold * HOTZONE_GOLD_RATE);
else
gold = (int) (gold * NORMAL_GOLD_RATE);
if (gold > 0) { if (gold > 0) {
MobLoot goldAmount = new MobLoot(mob, gold); MobLoot goldAmount = new MobLoot(mob, gold);
@ -315,43 +400,48 @@ public enum LootManager {
public static void GenerateLootDrop(Mob mob, int tableID, Boolean inHotzone) { public static void GenerateLootDrop(Mob mob, int tableID, Boolean inHotzone) {
try {
MobLoot toAdd = getGenTableItem(tableID, mob, inHotzone); MobLoot toAdd = getGenTableItem(tableID, mob, inHotzone);
if (toAdd != null) if (toAdd != null) {
toAdd.setIsID(true);
mob.getCharItemManager().addItemToInventory(toAdd); mob.getCharItemManager().addItemToInventory(toAdd);
} catch (Exception e) {
//TODO chase down loot generation error, affects roughly 2% of drops
int i = 0;
} }
} }
public static void GenerateEquipmentDrop(Mob mob) { public static void GenerateEquipmentDrop(Mob mob) {
if (mob == null || mob.getSafeZone())
return; // no equipment to drop in safezones
//do equipment here //do equipment here
int dropCount = 0; if (mob.getEquip() != null) {
if (mob.getEquip() != null) boolean isVorg = false;
for (MobEquipment me : mob.getEquip().values()) { for (MobEquipment me : mob.getEquip().values()) {
if (me.getDropChance() == 0) if (me.getDropChance() == 0)
continue; continue;
String name = me.getItemBase().getName().toLowerCase();
if (name.contains("vorgrim legionnaire's") || name.contains("vorgrim auxiliary's") ||name.contains("bellugh nuathal") || name.contains("crimson circle"))
isVorg = true;
float equipmentRoll = ThreadLocalRandom.current().nextInt(1, 100 + 1); float equipmentRoll = ThreadLocalRandom.current().nextInt(1, 100 + 1);
float dropChance = me.getDropChance() * 100; float dropChance = me.getDropChance() * 100;
ItemBase itemBase = me.getItemBase();
if(isVorg) {
mob.spawnTime = ThreadLocalRandom.current().nextInt(300, 2700);
dropChance = 10;
itemBase = getRandomVorg(itemBase);
}
if (equipmentRoll > dropChance) if (equipmentRoll > dropChance)
continue; continue;
MobLoot ml = new MobLoot(mob, me.getItemBase(), false); MobLoot ml = new MobLoot(mob, itemBase, false);
if (ml != null && dropCount < 1) {
ml.setIsID(true); ml.setIsID(true);
ml.setDurabilityCurrent((short) (ml.getDurabilityCurrent() - ThreadLocalRandom.current().nextInt(5) + 1)); ml.setDurabilityCurrent((short) (ml.getDurabilityCurrent() - ThreadLocalRandom.current().nextInt(5) + 1));
mob.getCharItemManager().addItemToInventory(ml); mob.getCharItemManager().addItemToInventory(ml);
dropCount = 1;
//break; // Exit on first successful roll.
} }
} }
} }
@ -367,8 +457,11 @@ public enum LootManager {
MobLoot lootItem = new MobLoot(mob, ItemBase.getItemBase(bse.itemBase), true); MobLoot lootItem = new MobLoot(mob, ItemBase.getItemBase(bse.itemBase), true);
if (lootItem != null) if (lootItem != null) {
mob.getCharItemManager().addItemToInventory(lootItem); mob.getCharItemManager().addItemToInventory(lootItem);
if(lootItem.getItemBase().isDiscRune() && !Mob.discDroppers.contains(mob))
Mob.AddDiscDropper(mob);
}
} }
public static void peddleFate(PlayerCharacter playerCharacter, Item gift) { public static void peddleFate(PlayerCharacter playerCharacter, Item gift) {
@ -392,7 +485,7 @@ public enum LootManager {
//check if player owns the gift he is trying to open //check if player owns the gift he is trying to open
if (itemMan.doesCharOwnThisItem(gift.getObjectUUID()) == false) if (!itemMan.doesCharOwnThisItem(gift.getObjectUUID()))
return; return;
//roll 1-100 for the gen table selection //roll 1-100 for the gen table selection
@ -413,12 +506,22 @@ public enum LootManager {
//create the item from the table, quantity is always 1 //create the item from the table, quantity is always 1
MobLoot winnings = new MobLoot(playerCharacter, ItemBase.getItemBase(selectedItem.cacheID), 1, false); ItemBase ib = ItemBase.getItemBase(selectedItem.cacheID);
if(ib.getUUID() == Warehouse.coalIB.getUUID()){
//no more coal, give gold instead
if (itemMan.getGoldInventory().getNumOfItems() + 250000 > 10000000) {
ErrorPopupMsg.sendErrorPopup(playerCharacter, 21);
return;
}
itemMan.addGoldToInventory(250000,false);
itemMan.updateInventory();
}else {
MobLoot winnings = new MobLoot(playerCharacter, ib, 1, false);
if (winnings == null) if (winnings == null)
return; return;
//early exit if the inventory of the player will not old the item //early exit if the inventory of the player will not hold the item
if (itemMan.hasRoomInventory(winnings.getItemBase().getWeight()) == false) { if (itemMan.hasRoomInventory(winnings.getItemBase().getWeight()) == false) {
ErrorPopupMsg.sendErrorPopup(playerCharacter, 21); ErrorPopupMsg.sendErrorPopup(playerCharacter, 21);
@ -455,3 +558,109 @@ public enum LootManager {
itemMan.updateInventory(); itemMan.updateInventory();
} }
} }
public static int rollRandomItem(int itemTable){
int returnedID = ItemTableEntry.getRandomItem(itemTable);
return returnedID;
}
public static ItemBase getRandomVorg(ItemBase itemBase){
int roll = 0;
if(vorg_ha_uuids.contains(itemBase.getUUID())) {
roll = ThreadLocalRandom.current().nextInt(0, 10);
switch (roll) {
case 1:
return ItemBase.getItemBase(vorg_ha_uuids.get(0));
case 2:
return ItemBase.getItemBase(vorg_ha_uuids.get(1));
case 3:
return ItemBase.getItemBase(vorg_ha_uuids.get(2));
case 4:
return ItemBase.getItemBase(vorg_ha_uuids.get(3));
case 5:
return ItemBase.getItemBase(vorg_ha_uuids.get(4));
case 6:
return ItemBase.getItemBase(vorg_ha_uuids.get(5));
case 7:
return ItemBase.getItemBase(vorg_ha_uuids.get(6));
case 8:
return ItemBase.getItemBase(vorg_ha_uuids.get(7));
default:
return ItemBase.getItemBase(vorg_ha_uuids.get(8));
}
}
if(vorg_ma_uuids.contains(itemBase.getUUID())) {
roll = ThreadLocalRandom.current().nextInt(0, 10);
switch (roll) {
case 1:
return ItemBase.getItemBase(vorg_ma_uuids.get(0));
case 2:
return ItemBase.getItemBase(vorg_ma_uuids.get(1));
case 3:
return ItemBase.getItemBase(vorg_ma_uuids.get(2));
case 4:
return ItemBase.getItemBase(vorg_ma_uuids.get(3));
case 5:
return ItemBase.getItemBase(vorg_ma_uuids.get(4));
case 6:
return ItemBase.getItemBase(vorg_ma_uuids.get(5));
case 7:
return ItemBase.getItemBase(vorg_ma_uuids.get(6));
default:
return ItemBase.getItemBase(vorg_ma_uuids.get(7));
}
}
if(vorg_la_uuids.contains(itemBase.getUUID())) {
roll = ThreadLocalRandom.current().nextInt(0, 10);
switch (roll) {
case 1:
return ItemBase.getItemBase(vorg_la_uuids.get(0));
case 2:
return ItemBase.getItemBase(vorg_la_uuids.get(1));
case 3:
return ItemBase.getItemBase(vorg_la_uuids.get(2));
case 4:
return ItemBase.getItemBase(vorg_la_uuids.get(3));
case 5:
return ItemBase.getItemBase(vorg_la_uuids.get(4));
case 6:
return ItemBase.getItemBase(vorg_la_uuids.get(5));
case 7:
return ItemBase.getItemBase(vorg_la_uuids.get(6));
default:
return ItemBase.getItemBase(vorg_la_uuids.get(7));
}
}
if(vorg_cloth_uuids.contains(itemBase.getUUID())) {
roll = ThreadLocalRandom.current().nextInt(0, 10);
switch (roll) {
case 1:
return ItemBase.getItemBase(vorg_cloth_uuids.get(0));
case 2:
return ItemBase.getItemBase(vorg_cloth_uuids.get(1));
case 3:
return ItemBase.getItemBase(vorg_cloth_uuids.get(2));
case 4:
return ItemBase.getItemBase(vorg_cloth_uuids.get(3));
default:
return ItemBase.getItemBase(vorg_cloth_uuids.get(4));
}
}
return null;
}
public static void DropPresent(Mob mob){
int random = ThreadLocalRandom.current().nextInt(ItemBase.AnniverseryGifts.size());
int presentID = ItemBase.AnniverseryGifts.get(random);
ItemBase presentBase = ItemBase.getItemBase(presentID);
if(presentBase != null){
MobLoot lootItem = new MobLoot(mob, presentBase, true);
mob.getCharItemManager().addItemToInventory(lootItem);
}
}
}

26
src/engine/gameManager/MaintenanceManager.java

@ -24,7 +24,7 @@ public enum MaintenanceManager {
public static void setMaintDateTime(Building building, LocalDateTime maintDate) { public static void setMaintDateTime(Building building, LocalDateTime maintDate) {
building.maintDateTime = maintDate; building.maintDateTime = maintDate.withHour(1).withMinute(0).withSecond(0);
DbManager.BuildingQueries.updateMaintDate(building); DbManager.BuildingQueries.updateMaintDate(building);
} }
@ -49,19 +49,15 @@ public enum MaintenanceManager {
if (chargeUpkeep(building) == false) if (chargeUpkeep(building) == false)
derankList.add(building); derankList.add(building);
} else
// Reset maintenance dates for these buildings
for (Building building : maintList) {
setMaintDateTime(building, LocalDateTime.now().plusDays(7)); setMaintDateTime(building, LocalDateTime.now().plusDays(7));
} }
// Derak or destroy buildings that did not
// have funds available.
for (Building building : derankList) for (Building building : derankList) {
building.destroyOrDerank(null); building.destroyOrDerank(null);
if(building.getRank() > 0)
setMaintDateTime(building, LocalDateTime.now().plusDays(1));
}
Logger.info("Structures: " + buildingList.size() + " Maint: " + maintList.size() + " Derank: " + derankList.size()); Logger.info("Structures: " + buildingList.size() + " Maint: " + maintList.size() + " Derank: " + derankList.size());
} }
@ -98,6 +94,10 @@ public enum MaintenanceManager {
continue; continue;
} }
//only ToL pays maintenance
if(building.getBlueprint().getBuildingGroup() != null && !building.getBlueprint().getBuildingGroup().equals(Enum.BuildingGroup.TOL))
continue;
// No maintenance on banestones omfg // No maintenance on banestones omfg
if (building.getBlueprint().getBuildingGroup().equals(Enum.BuildingGroup.BANESTONE)) if (building.getBlueprint().getBuildingGroup().equals(Enum.BuildingGroup.BANESTONE))
@ -222,12 +222,6 @@ public enum MaintenanceManager {
if ((hasFunds == false) || if ((hasFunds == false) ||
((building.getRank() == 8) && !hasResources)) { ((building.getRank() == 8) && !hasResources)) {
// Add cash back to strongbox for lost rank if the building isn't being destroyed
// and it's not an R8 deranking
if ((building.getRank() > 1) && (building.getRank() < 8)) {
building.setStrongboxValue(building.getStrongboxValue() + building.getBlueprint().getRankCost(Math.min(building.getRank(), 7)));
}
return false; // Early exit for having failed to meet maintenance return false; // Early exit for having failed to meet maintenance
} }

17
src/engine/gameManager/SimulationManager.java

@ -10,10 +10,7 @@ package engine.gameManager;
import engine.Enum; import engine.Enum;
import engine.Enum.GameObjectType; import engine.Enum.GameObjectType;
import engine.objects.AbstractGameObject; import engine.objects.*;
import engine.objects.City;
import engine.objects.PlayerCharacter;
import engine.objects.Runegate;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@ -33,7 +30,7 @@ public enum SimulationManager {
SERVERHEARTBEAT; SERVERHEARTBEAT;
private static final long CITY_PULSE = 2000; private static final long CITY_PULSE = 2000;
private static final long RUNEGATE_PULSE = 3000; private static final long RUNEGATE_PULSE = 1000;
private static final long UPDATE_PULSE = 1000; private static final long UPDATE_PULSE = 1000;
private static final long FlIGHT_PULSE = 100; private static final long FlIGHT_PULSE = 100;
public static Duration executionTime = Duration.ofNanos(1); public static Duration executionTime = Duration.ofNanos(1);
@ -203,8 +200,12 @@ public enum SimulationManager {
city = (City) cityObject; city = (City) cityObject;
city.onEnter(); city.onEnter();
} }
for(Mine mine : Mine.getMines()){
if(mine != null && mine.isActive)
mine.onEnter();
}
_cityPulseTime = System.currentTimeMillis() + CITY_PULSE; _cityPulseTime = System.currentTimeMillis() + CITY_PULSE;
} }
/* /*
@ -214,6 +215,10 @@ public enum SimulationManager {
private void pulseRunegates() { private void pulseRunegates() {
for (Runegate runegate : Runegate._runegates.values()) { for (Runegate runegate : Runegate._runegates.values()) {
for(Portal portal : runegate._portals)
if(!portal.isActive())
portal.activate(false);
runegate.collidePortals(); runegate.collidePortals();
} }

92
src/engine/gameManager/ZergManager.java

@ -0,0 +1,92 @@
package engine.gameManager;
import engine.objects.Guild;
public class ZergManager {
public static float getCurrentMultiplier(int count, int maxCount){
switch(maxCount) {
case 3:
return getMultiplier3Man(count);
case 5:
return getMultiplier5Man(count);
case 10:
return getMultiplier10Man(count);
default:
return getMultiplier20Man(count);
}
}
public static float getMultiplier3Man(int count) {
if(count < 4)
return 1.0f;
if(count > 6)
return 0.0f;
switch(count){
case 4:
return 0.75f;
case 5:
return 0.60f;
case 6:
return 0.37f;
}
return 1.0f;
}
public static float getMultiplier5Man(int count) {
if(count < 6)
return 1.0f;
if(count > 10)
return 0.0f;
switch(count){
case 6:
return 0.75f;
case 7:
return 0.67f;
case 8:
return 0.56f;
case 9:
return 0.43f;
case 10:
return 0.25f;
}
return 1.0f;
}
public static float getMultiplier10Man(int count) {
if(count < 11)
return 1.0f;
if(count > 20)
return 0.0f;
switch(count){
case 11:
return 0.75f;
case 12:
return 0.71f;
case 13:
return 0.67f;
case 14:
return 0.62f;
case 15:
return 0.56f;
case 16:
return 0.50f;
case 17:
return 0.43f;
case 18:
return 0.35f;
case 19:
return 0.25f;
case 20:
return 0.14f;
}
return 1.0f;
}
public static float getMultiplier20Man(int count) {
return getMultiplier10Man(count * 2);
}
}

73
src/engine/gameManager/ZoneManager.java

@ -19,14 +19,12 @@ import engine.objects.Building;
import engine.objects.City; import engine.objects.City;
import engine.objects.Zone; import engine.objects.Zone;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
/* /*
* Class contains methods and structures which * Class contains methods and structures which
@ -109,20 +107,6 @@ public enum ZoneManager {
} }
// Returns the number of available hotZones
// remaining in this cycle (1am)
public static int availableHotZones() {
int count = 0;
for (Zone zone : ZoneManager.macroZones)
if (ZoneManager.validHotZone(zone))
count = count + 1;
return count;
}
// Resets the availability of hotZones // Resets the availability of hotZones
// for this cycle // for this cycle
@ -217,63 +201,6 @@ public enum ZoneManager {
ZoneManager.playerCityZones.add(zone); ZoneManager.playerCityZones.add(zone);
} }
public static final void generateAndSetRandomHotzone() {
Zone hotZone;
ArrayList<Integer> zoneArray = new ArrayList<>();
if (ZoneManager.macroZones.isEmpty())
return;
// Reset hotZone availability if none are left.
if (ZoneManager.availableHotZones() == 0)
ZoneManager.resetHotZones();
for (Zone zone : ZoneManager.macroZones)
if (validHotZone(zone))
zoneArray.add(zone.getObjectUUID());
int entryIndex = ThreadLocalRandom.current().nextInt(zoneArray.size());
hotZone = ZoneManager.getZoneByUUID(zoneArray.get(entryIndex));
if (hotZone == null) {
Logger.error("Hotzone is null");
return;
}
ZoneManager.setHotZone(hotZone);
}
public static final boolean validHotZone(Zone zone) {
if (zone.getSafeZone() == (byte) 1)
return false; // no safe zone hotzones// if (this.hotzone == null)
if (zone.getNodes().isEmpty())
return false;
if (zone.equals(ZoneManager.seaFloor))
return false;
//no duplicate hotZones
if (zone.hasBeenHotzone == true)
return false;
// Enforce min level
if (zone.minLvl < Integer.parseInt(ConfigManager.MB_HOTZONE_MIN_LEVEL.getValue()))
return false;
if (ZoneManager.hotZone != null)
return ZoneManager.hotZone.getObjectUUID() != zone.getObjectUUID();
return true;
}
// Converts world coordinates to coordinates local to a given zone. // Converts world coordinates to coordinates local to a given zone.
public static Vector3fImmutable worldToLocal(Vector3fImmutable worldVector, public static Vector3fImmutable worldToLocal(Vector3fImmutable worldVector,

14
src/engine/loot/ItemTableEntry.java

@ -9,10 +9,12 @@
package engine.loot; package engine.loot;
import engine.gameManager.LootManager; import engine.gameManager.LootManager;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class ItemTableEntry { public class ItemTableEntry {
public int minRoll; public int minRoll;
@ -42,4 +44,16 @@ public class ItemTableEntry {
return itemTableEntry; return itemTableEntry;
} }
public static Integer getRandomItem(int itemTable) {
int id = 0;
List<ItemTableEntry> itemTableEntryList;
itemTableEntryList = LootManager._itemTables.get(itemTable);
if(itemTableEntryList != null){
id = itemTableEntryList.get(ThreadLocalRandom.current().nextInt(0,itemTableEntryList.size() - 1)).cacheID;
}
return id;
}
} }

22
src/engine/mobileAI/MobAI.java

@ -625,7 +625,7 @@ public class MobAI {
//check to send mob home for player guards to prevent exploit of dragging guards away and then teleporting //check to send mob home for player guards to prevent exploit of dragging guards away and then teleporting
if (mob.BehaviourType.ordinal() != Enum.MobBehaviourType.Pet1.ordinal())
CheckToSendMobHome(mob); CheckToSendMobHome(mob);
return; return;
@ -646,9 +646,6 @@ public class MobAI {
return; return;
} }
if (mob.BehaviourType.ordinal() != Enum.MobBehaviourType.Pet1.ordinal())
CheckToSendMobHome(mob);
if (mob.getCombatTarget() != null) { if (mob.getCombatTarget() != null) {
if (mob.getCombatTarget().isAlive() == false) { if (mob.getCombatTarget().isAlive() == false) {
@ -874,9 +871,12 @@ public class MobAI {
} }
} }
} }
} else if (System.currentTimeMillis() > (aiAgent.deathTime + (aiAgent.spawnTime * 1000))) { } else if (System.currentTimeMillis() > (aiAgent.deathTime + (aiAgent.spawnTime * 1000L))) {
if(Mob.discDroppers.contains(aiAgent))
return;
if (Zone.respawnQue.contains(aiAgent) == false) { if (!Zone.respawnQue.contains(aiAgent)) {
Zone.respawnQue.add(aiAgent); Zone.respawnQue.add(aiAgent);
} }
} }
@ -911,6 +911,11 @@ public class MobAI {
private static void CheckToSendMobHome(Mob mob) { private static void CheckToSendMobHome(Mob mob) {
if(mob.BehaviourType.equals(Enum.MobBehaviourType.Pet1)){
if(mob.loc.distanceSquared(mob.getOwner().loc) > 60 * 60)
mob.teleport(mob.getOwner().loc);
return;
}
try { try {
if (mob.BehaviourType.isAgressive) { if (mob.BehaviourType.isAgressive) {
@ -922,9 +927,6 @@ public class MobAI {
} }
} }
if (mob.getCombatTarget() != null && CombatUtilities.inRange2D(mob, mob.getCombatTarget(), MobAIThread.AI_BASE_AGGRO_RANGE * 0.5f))
return;
if (mob.isPlayerGuard() && !mob.despawned) { if (mob.isPlayerGuard() && !mob.despawned) {
City current = ZoneManager.getCityAtLocation(mob.getLoc()); City current = ZoneManager.getCityAtLocation(mob.getLoc());
@ -1006,7 +1008,7 @@ public class MobAI {
//dont scan self. //dont scan self.
if (mob.equals(awoMob) || (mob.agentType.equals(Enum.AIAgentType.GUARD)) == true) if (mob.equals(awoMob) || (mob.agentType.equals(Enum.AIAgentType.GUARD)) || (mob.agentType.equals(Enum.AIAgentType.PET)))
continue; continue;
Mob aggroMob = (Mob) awoMob; Mob aggroMob = (Mob) awoMob;

195
src/engine/net/client/ClientMessagePump.java

@ -560,12 +560,30 @@ public class ClientMessagePump implements NetMsgHandler {
if (!itemManager.inventoryContains(i)) if (!itemManager.inventoryContains(i))
return; return;
if (i.isCanDestroy()) //cannot delete gold
if (itemManager.delete(i) == true) { if(i.getItemBaseID() == 7)
return;
if (i.isCanDestroy()) {
int goldValue = i.getBaseValue();
if (i.getItemBase().isRune())
goldValue = 500000;
if (i.getItemBaseID() == 980066)
goldValue = 0;
if(itemManager.getGoldInventory().getNumOfItems() + goldValue > 10000000)
return;
if (itemManager.delete(i)) {
if (goldValue > 0)
itemManager.addGoldToInventory(goldValue, false);
itemManager.updateInventory();
Dispatch dispatch = Dispatch.borrow(sourcePlayer, msg); Dispatch dispatch = Dispatch.borrow(sourcePlayer, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
} }
}
} }
private static void ackBankWindowOpened(AckBankWindowOpenedMsg msg, ClientConnection origin) { private static void ackBankWindowOpened(AckBankWindowOpenedMsg msg, ClientConnection origin) {
@ -1243,6 +1261,8 @@ public class ClientMessagePump implements NetMsgHandler {
cost = sell.getBaseValue(); cost = sell.getBaseValue();
if(sell.getItemBaseID() == 980066)
cost = 0;
//apply damaged value reduction //apply damaged value reduction
float durabilityCurrent = sell.getDurabilityCurrent(); float durabilityCurrent = sell.getDurabilityCurrent();
@ -1343,6 +1363,14 @@ public class ClientMessagePump implements NetMsgHandler {
NPC npc = NPC.getFromCache(msg.getNpcID()); NPC npc = NPC.getFromCache(msg.getNpcID());
switch(npc.getContractID()){
case 900:
case 1201:
case 1202:
npc.sellPercent = 0.0f;
break;
}
if (npc == null) if (npc == null)
return; return;
@ -1358,219 +1386,182 @@ public class ClientMessagePump implements NetMsgHandler {
} }
private static void buyFromNPC(BuyFromNPCMsg msg, ClientConnection origin) { private static void buyFromNPC(BuyFromNPCMsg msg, ClientConnection origin) {
PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin); PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin);
if (sourcePlayer == null) if (sourcePlayer == null)
return; return;
if (origin.buyLock.tryLock()) { if (origin.buyLock.tryLock()) {
try { try {
CharacterItemManager itemMan = sourcePlayer.getCharItemManager(); CharacterItemManager itemMan = sourcePlayer.getCharItemManager();
if (itemMan == null) {
if (itemMan == null)
return; return;
}
NPC npc = NPC.getFromCache(msg.getNPCID()); NPC npc = NPC.getFromCache(msg.getNPCID());
if (npc == null) {
if (npc == null)
return; return;
}
Item gold = itemMan.getGoldInventory(); Item gold = itemMan.getGoldInventory();
if (gold == null) {
if (gold == null)
return; return;
}
Item buy = null; Item buy = null;
if (msg.getItemType() == GameObjectType.MobEquipment.ordinal()) { if (msg.getItemType() == GameObjectType.MobEquipment.ordinal()) {
ArrayList<MobEquipment> sellInventory = npc.getContract().getSellInventory(); ArrayList<MobEquipment> sellInventory = npc.getContract().getSellInventory();
if (sellInventory == null) if (sellInventory == null) {
return; return;
}
for (MobEquipment me : sellInventory) { for (MobEquipment me : sellInventory) {
if (me.getObjectUUID() == msg.getItemID()) { if (me.getObjectUUID() == msg.getItemID()) {
ItemBase ib = me.getItemBase(); ItemBase ib = me.getItemBase();
if (ib == null) if (ib == null) {
return; return;
}
//test room available for item //test room available for item
if (!itemMan.hasRoomInventory(ib.getWeight())) if (!itemMan.hasRoomInventory(ib.getWeight())) {
return; return;
}
int cost = me.getMagicValue(); int cost = me.getMagicValue();
float bargain = sourcePlayer.getBargain(); float bargain = sourcePlayer.getBargain();
switch(npc.getContractID()){
case 1201:
cost = ItemBase.getDiscPrice(ib.getUUID());
bargain = 0;
break;
case 1202:
cost = ItemBase.getStatPrice(ib.getUUID());
bargain = 0;
break;
case 900:
cost = Warehouse.getCostForResource(ib.getUUID()) * Warehouse.getSellStackSize(ib.getUUID());
bargain = 0;
break;
}
float profit = npc.getSellPercent(sourcePlayer) - bargain; float profit = npc.getSellPercent(sourcePlayer) - bargain;
if(me.getItemBase().getType().equals(ItemType.POTION))
profit -= 1.0f;
if (profit < 1) if (profit < 1)
profit = 1; profit = 1;
cost *= profit; cost *= profit;
if(npc.getContractID() == 1502041)
cost = 2;
if (gold.getNumOfItems() - cost < 0) { if (gold.getNumOfItems() - cost < 0) {
//dont' have enough goldItem exit! //dont' have enough goldItem exit!
// chatMan.chatSystemInfo(pc, "" + "You dont have enough gold."); // chatMan.chatSystemInfo(pc, "" + "You dont have enough gold.");
return; return;
} }
Building b = (!npc.isStatic()) ? npc.getBuilding() : null; Building b = (!npc.isStatic()) ? npc.getBuilding() : null;
if (b != null && b.getProtectionState().equals(ProtectionState.NPC)) if (b != null && b.getProtectionState().equals(ProtectionState.NPC))
b = null; b = null;
int buildingDeposit = cost - me.getMagicValue(); int buildingDeposit = cost - me.getMagicValue();
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold()) { if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold() && !b.isOwnerIsNPC()) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206); ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206);
return; return;
} }
if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) { if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) {
// chatMan.chatSystemInfo(pc, "" + "You Failed to buy the item."); // chatMan.chatSystemInfo(pc, "" + "You Failed to buy the item.");
ChatManager.chatSystemError(sourcePlayer, "Failed To Buy Item");
return; return;
} }
if(me.getItemBase().getType().equals(ItemType.RESOURCE) && npc.getContractID() == 900){
buy = Item.createItemForPlayer(sourcePlayer, ib); handleResourcePurchase(me,itemMan,sourcePlayer,ib);
}else {
buy = Item.createItemForPlayer(sourcePlayer, ib, me.fromNoob);
if (buy != null) { if (buy != null) {
me.transferEnchants(buy); me.transferEnchants(buy);
itemMan.addItemToInventory(buy); itemMan.addItemToInventory(buy);
if(npc.contractUUID == 900 && buy.getItemBaseID() == 1705032){
buy.setNumOfItems(10);
DbManager.ItemQueries.UPDATE_NUM_ITEMS(buy,buy.getNumOfItems());
}
//itemMan.updateInventory(); //itemMan.updateInventory();
} }
} }
} }
}
} else if (msg.getItemType() == GameObjectType.Item.ordinal()) { } else if (msg.getItemType() == GameObjectType.Item.ordinal()) {
CharacterItemManager npcCim = npc.getCharItemManager(); CharacterItemManager npcCim = npc.getCharItemManager();
if (npcCim == null) if (npcCim == null)
return; return;
buy = Item.getFromCache(msg.getItemID()); buy = Item.getFromCache(msg.getItemID());
if (buy == null) if (buy == null)
return; return;
ItemBase ib = buy.getItemBase(); ItemBase ib = buy.getItemBase();
if (ib == null) if (ib == null)
return; return;
if (!npcCim.inventoryContains(buy)) if (!npcCim.inventoryContains(buy))
return; return;
//test room available for item //test room available for item
if (!itemMan.hasRoomInventory(ib.getWeight())) if (!itemMan.hasRoomInventory(ib.getWeight()))
return; return;
//TODO test cost and subtract goldItem //TODO test cost and subtract goldItem
//TODO CHnage this if we ever put NPc city npcs in buildings. //TODO CHnage this if we ever put NPc city npcs in buildings.
int cost = buy.getBaseValue(); int cost = buy.getBaseValue();
if (buy.isID() || buy.isCustomValue()) if (buy.isID() || buy.isCustomValue())
cost = buy.getMagicValue(); cost = buy.getMagicValue();
float bargain = sourcePlayer.getBargain(); float bargain = sourcePlayer.getBargain();
float profit = npc.getSellPercent(sourcePlayer) - bargain; float profit = npc.getSellPercent(sourcePlayer) - bargain;
if (profit < 1) if (profit < 1)
profit = 1; profit = 1;
if (!buy.isCustomValue()) if (!buy.isCustomValue())
cost *= profit; cost *= profit;
else else
cost = buy.getValue(); cost = buy.getValue();
if (gold.getNumOfItems() - cost < 0) { if (gold.getNumOfItems() - cost < 0) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 128); // Insufficient Gold ErrorPopupMsg.sendErrorPopup(sourcePlayer, 128); // Insufficient Gold
return; return;
} }
Building b = (!npc.isStatic()) ? npc.getBuilding() : null; Building b = (!npc.isStatic()) ? npc.getBuilding() : null;
if (b != null) if (b != null)
if (b.getProtectionState().equals(ProtectionState.NPC)) if (b.getProtectionState().equals(ProtectionState.NPC))
b = null; b = null;
int buildingDeposit = cost; int buildingDeposit = cost;
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold() && !b.isOwnerIsNPC()) {
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold()) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206); ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206);
return; return;
} }
if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) { if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 110); ErrorPopupMsg.sendErrorPopup(sourcePlayer, 110);
return; return;
} }
if (buy != null) if (buy != null)
itemMan.buyFromNPC(buy, npc); itemMan.buyFromNPC(buy, npc);
} else if (msg.getItemType() == GameObjectType.MobLoot.ordinal()) { } else if (msg.getItemType() == GameObjectType.MobLoot.ordinal()) {
CharacterItemManager npcCim = npc.getCharItemManager(); CharacterItemManager npcCim = npc.getCharItemManager();
if (npcCim == null) if (npcCim == null)
return; return;
buy = MobLoot.getFromCache(msg.getItemID()); buy = MobLoot.getFromCache(msg.getItemID());
if (buy == null) if (buy == null)
return; return;
ItemBase ib = buy.getItemBase(); ItemBase ib = buy.getItemBase();
if (ib == null) if (ib == null)
return; return;
if (!npcCim.inventoryContains(buy)) if (!npcCim.inventoryContains(buy))
return; return;
//test room available for item //test room available for item
if (!itemMan.hasRoomInventory(ib.getWeight())) if (!itemMan.hasRoomInventory(ib.getWeight()))
return; return;
//TODO test cost and subtract goldItem //TODO test cost and subtract goldItem
//TODO CHnage this if we ever put NPc city npcs in buildings. //TODO CHnage this if we ever put NPc city npcs in buildings.
int cost = buy.getMagicValue(); int cost = buy.getMagicValue();
cost *= npc.getSellPercent(sourcePlayer); cost *= npc.getSellPercent(sourcePlayer);
if (gold.getNumOfItems() - cost < 0) { if (gold.getNumOfItems() - cost < 0) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 128); // Insufficient Gold ErrorPopupMsg.sendErrorPopup(sourcePlayer, 128); // Insufficient Gold
return; return;
} }
Building b = (!npc.isStatic()) ? npc.getBuilding() : null; Building b = (!npc.isStatic()) ? npc.getBuilding() : null;
if (b != null && b.getProtectionState().equals(ProtectionState.NPC)) if (b != null && b.getProtectionState().equals(ProtectionState.NPC))
b = null; b = null;
int buildingDeposit = cost; int buildingDeposit = cost;
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold() && !b.isOwnerIsNPC()) {
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold()) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206); ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206);
return; return;
} }
if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) if (!itemMan.buyFromNPC(b, cost, buildingDeposit))
return; return;
if (buy != null) if (buy != null)
itemMan.buyFromNPC(buy, npc); itemMan.buyFromNPC(buy, npc);
} else } else
return; return;
if (buy != null) { if (buy != null) {
msg.setItem(buy); msg.setItem(buy);
//send the buy message back to update player //send the buy message back to update player
// msg.setItemType(buy.getObjectType().ordinal()); // msg.setItemType(buy.getObjectType().ordinal());
@ -1579,14 +1570,43 @@ public class ClientMessagePump implements NetMsgHandler {
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
itemMan.updateInventory(); itemMan.updateInventory();
} }
} finally { } finally {
origin.buyLock.unlock(); origin.buyLock.unlock();
} }
} else { } else {
ErrorPopupMsg.sendErrorPopup(origin.getPlayerCharacter(), 12); // All production slots taken ErrorPopupMsg.sendErrorPopup(origin.getPlayerCharacter(), 12); // All production slots taken
} }
}
public static void handleResourcePurchase(MobEquipment me, CharacterItemManager itemMan, PlayerCharacter sourcePlayer, ItemBase ib){
boolean stacked = false;
int buystack = Warehouse.getSellStackSize(me.getItemBase().getUUID());
for(Item item : itemMan.getInventory()){
int itemID = item.getItemBaseID();
int meID = me.getItemBase().getUUID();
if(itemID == meID){
if(Warehouse.maxResources.isEmpty())
Warehouse.getMaxResources();
int maxStack = Warehouse.maxResources.get(itemID);
if(maxStack > item.getNumOfItems() + buystack){
item.setNumOfItems(item.getNumOfItems() + buystack);
stacked = true;
itemMan.updateInventory();
DbManager.ItemQueries.UPDATE_NUM_ITEMS(item,item.getNumOfItems());
break;
}
}
}
if(!stacked){
Item buy = Item.createItemForPlayer(sourcePlayer, ib, false);
if (buy != null) {
me.transferEnchants(buy);
itemMan.addItemToInventory(buy);
buy.setNumOfItems(buystack);
DbManager.ItemQueries.UPDATE_NUM_ITEMS(buy,buy.getNumOfItems());
}
}
itemMan.updateInventory();
} }
private static void Repair(RepairMsg msg, ClientConnection origin) { private static void Repair(RepairMsg msg, ClientConnection origin) {
@ -1646,14 +1666,17 @@ public class ClientMessagePump implements NetMsgHandler {
max *= (1 + (durMod * 0.01f)); max *= (1 + (durMod * 0.01f));
if (dur >= max || dur < 1) { if (dur >= max || dur < 1) {
//redundancy message to clear item from window in client //redundancy message to clear item from window in client
if (!DbManager.ItemQueries.SET_DURABILITY(toRepair, dur))
return;
toRepair.setDurabilityCurrent(max); toRepair.setDurabilityCurrent(max);
msg.setupRepairAck(max - dur); msg.setupRepairAck(max - dur);
dispatch = Dispatch.borrow(player, msg); dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
return; return;
} }
//TODO get cost to repair
int cost = (int) ((max - dur) * 80.1); int cost = (int)((toRepair.getMagicValue()/max*(max - dur)) + (npc.getRepairCost() * npc.buyPercent));
Building b = (!npc.isStatic()) ? npc.getBuilding() : null; Building b = (!npc.isStatic()) ? npc.getBuilding() : null;
if (b != null) if (b != null)

15
src/engine/net/client/handlers/ArcMineChangeProductionMsgHandler.java

@ -11,6 +11,7 @@ import engine.objects.GuildStatusController;
import engine.objects.Mine; import engine.objects.Mine;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.objects.Resource; import engine.objects.Resource;
import org.pmw.tinylog.Logger;
/* /*
* @Author: * @Author:
@ -35,26 +36,28 @@ public class ArcMineChangeProductionMsgHandler extends AbstractClientMsgHandler
//TODO verify this against the warehouse? //TODO verify this against the warehouse?
if (GuildStatusController.isInnerCouncil(playerCharacter.getGuildStatus()) == false) // is this only GL? if (!GuildStatusController.isInnerCouncil(playerCharacter.getGuildStatus())) // is this only GL?
return true; return true;
Mine mine = Mine.getMine(changeProductionMsg.getMineID()); Mine mine = Mine.getMine(changeProductionMsg.getMineID());
if (mine == null) if (mine == null) {
Logger.error("Player Character: " + playerCharacter.getName() + " Tried To Change Mine: " + changeProductionMsg.getMineID() + " and Mine was Null");
return true; return true;
}
//make sure mine belongs to guild //make sure mine belongs to guild
if (mine.getOwningGuild().isEmptyGuild() || if (mine.getOwningGuild().isEmptyGuild() || mine.getOwningGuild().getObjectUUID() != playerCharacter.getGuild().getObjectUUID())
mine.getOwningGuild().getObjectUUID() != playerCharacter.getGuild().getObjectUUID())
return true; return true;
//make sure valid resource //make sure valid resource
Resource resource = Resource.resourceByHash.get(changeProductionMsg.getResourceHash()); Resource resource = Resource.resourceByHash.get(changeProductionMsg.getResourceHash());
if (resource == null) if (resource == null) {
Logger.error("Player Character: " + playerCharacter.getName() + " Tried To Change Mine: " + changeProductionMsg.getMineID() + " and Resource was Null");
return true; return true;
}
//update resource //update resource

2
src/engine/net/client/handlers/CityDataHandler.java

@ -63,7 +63,7 @@ public class CityDataHandler extends AbstractClientMsgHandler {
// If the hotZone has changed then update the client's map accordingly. // If the hotZone has changed then update the client's map accordingly.
if (playerCharacter.getTimeStamp("hotzoneupdate") <= ZoneManager.hotZoneLastUpdate.toEpochMilli() && ZoneManager.hotZone != null) { if (playerCharacter.getTimestamps().containsKey("hotzoneupdate") && playerCharacter.getTimeStamp("hotzoneupdate") <= ZoneManager.hotZoneLastUpdate.toEpochMilli() && ZoneManager.hotZone != null) {
HotzoneChangeMsg hotzoneChangeMsg = new HotzoneChangeMsg(Enum.GameObjectType.Zone.ordinal(), ZoneManager.hotZone.getObjectUUID()); HotzoneChangeMsg hotzoneChangeMsg = new HotzoneChangeMsg(Enum.GameObjectType.Zone.ordinal(), ZoneManager.hotZone.getObjectUUID());
dispatch = Dispatch.borrow(playerCharacter, hotzoneChangeMsg); dispatch = Dispatch.borrow(playerCharacter, hotzoneChangeMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);

57
src/engine/net/client/handlers/MerchantMsgHandler.java

@ -17,6 +17,7 @@ import engine.powers.PowersBase;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Objects;
/* /*
* @Author: * @Author:
@ -105,7 +106,7 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
// Validate player can obtain blessing // Validate player can obtain blessing
if (GuildStatusController.isGuildLeader(player.getGuildStatus()) == false) { if (!GuildStatusController.isGuildLeader(player.getGuildStatus())) {
ErrorPopupMsg.sendErrorPopup(player, 173); // You must be the leader of a guild to receive a blessing ErrorPopupMsg.sendErrorPopup(player, 173); // You must be the leader of a guild to receive a blessing
return; return;
} }
@ -126,12 +127,12 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
realm = RealmMap.getRealmForCity(city); realm = RealmMap.getRealmForCity(city);
if (realm.getCanBeClaimed() == false) { if (!realm.getCanBeClaimed()) {
ErrorPopupMsg.sendErrorPopup(player, 180); // This territory cannot be ruled by anyone ErrorPopupMsg.sendErrorPopup(player, 180); // This territory cannot be ruled by anyone
return; return;
} }
if (realm.isRuled() == true) { if (realm.isRuled()) {
ErrorPopupMsg.sendErrorPopup(player, 178); // This territory is already claimed ErrorPopupMsg.sendErrorPopup(player, 178); // This territory is already claimed
return; return;
} }
@ -142,12 +143,12 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
} }
private static void requestBoon(MerchantMsg msg, ClientConnection origin, PlayerCharacter player, NPC npc) { private static void requestBoon(PlayerCharacter player, NPC npc) {
Building shrineBuilding; Building shrineBuilding;
Shrine shrine; Shrine shrine;
if (npc.getGuild() != player.getGuild()) if (!npc.getGuild().getNation().equals(player.getGuild().getNation()))
return; return;
shrineBuilding = npc.getBuilding(); shrineBuilding = npc.getBuilding();
@ -155,7 +156,7 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
if (shrineBuilding == null) if (shrineBuilding == null)
return; return;
if (shrineBuilding.getBlueprint() != null && shrineBuilding.getBlueprint().getBuildingGroup() != engine.Enum.BuildingGroup.SHRINE) if (shrineBuilding.getBlueprint() != null && !shrineBuilding.getBlueprint().getBuildingGroup().equals(engine.Enum.BuildingGroup.SHRINE))
return; return;
if (shrineBuilding.getRank() == -1) if (shrineBuilding.getRank() == -1)
@ -171,11 +172,9 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
return; return;
} }
//already haz boon.
if (player.containsEffect(shrine.getShrineType().getPowerToken())) { if (player.containsEffect(shrine.getShrineType().getPowerToken())) {
ErrorPopupMsg.sendErrorPopup(player, 199); //remove old boon to apply new one, allows boon refreshing
return; player.effects.remove(PowersManager.getPowerByToken(shrine.getShrineType().getPowerToken()).name);
} }
if (!Shrine.canTakeFavor(player, shrine)) if (!Shrine.canTakeFavor(player, shrine))
@ -191,16 +190,34 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
return; return;
} }
int rank = shrine.getRank(); int trains = 0;
//R8 trees always get atleast rank 2 boons. rank uses index, where 0 is first place, 1 is second, etc... switch(npc.getRank()){
if (shrineBuilding.getCity() != null && shrineBuilding.getCity().getTOL() != null && shrineBuilding.getCity().getTOL().getRank() == 8) case 1:
if (rank != 0) trains = 5;
rank = 1; break;
int trains = 40 - (rank * 10); case 2:
if (trains < 0) trains = 10;
trains = 0; break;
case 3:
trains = 15;
break;
case 4:
trains = 20;
break;
case 5:
trains = 25;
break;
case 6:
trains = 30;
break;
case 7:
trains = 35;
break;
}
if(Objects.requireNonNull(shrineBuilding.getCity()).getTOL() != null && shrineBuilding.getCity().getTOL().getRank() == 8)
trains += 5;
//System.out.println(trains);
PowersManager.applyPower(player, player, player.getLoc(), shrinePower.getToken(), trains, false); PowersManager.applyPower(player, player, player.getLoc(), shrinePower.getToken(), trains, false);
ChatManager.chatGuildInfo(player.getGuild(), player.getName() + " has recieved a boon costing " + 1 + " point of favor."); ChatManager.chatGuildInfo(player.getGuild(), player.getName() + " has recieved a boon costing " + 1 + " point of favor.");
shrineBuilding.addEffectBit(1000000 << 2); shrineBuilding.addEffectBit(1000000 << 2);
@ -420,7 +437,7 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
if (isHermit(npc)) if (isHermit(npc))
requestHermitBlessing(msg, origin, player, npc); requestHermitBlessing(msg, origin, player, npc);
else else
requestBoon(msg, origin, player, npc); requestBoon(player, npc);
break; break;
case 15: case 15:
LeaderboardMessage lbm = new LeaderboardMessage(); LeaderboardMessage lbm = new LeaderboardMessage();

20
src/engine/net/client/handlers/ObjectActionMsgHandler.java

@ -421,31 +421,12 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
itemMan.consume(item); itemMan.consume(item);
} }
break; break;
//ANNIVERSERY GIFT
case 31: case 31:
// *** Disabled for now: Needs bootyset created
//if (ib.getUUID() == 971012) {
// int random = ThreadLocalRandom.current().nextInt(ItemBase.AnniverseryGifts.size());
// int annyID = ItemBase.AnniverseryGifts.get(random);
// ItemBase annyIB = ItemBase.getItemBase(annyID);
// if (annyIB != null) {
// Item gift = MobLoot.createItemForPlayer(player, annyIB);
// if (gift != null) {
// itemMan.addItemToInventory(gift);
// itemMan.consume(item);
// }
// }
// break;
//}
LootManager.peddleFate(player,item); LootManager.peddleFate(player,item);
break; break;
case 30: //water bucket case 30: //water bucket
case 8: //potions, tears of saedron case 8: //potions, tears of saedron
case 5: //runes, petition, warrant, scrolls case 5: //runes, petition, warrant, scrolls
if (uuid > 3000 && uuid < 3050) { //Discipline Runes if (uuid > 3000 && uuid < 3050) { //Discipline Runes
if (ApplyRuneMsg.applyRune(uuid, origin, player)) { if (ApplyRuneMsg.applyRune(uuid, origin, player)) {
@ -528,7 +509,6 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
} }
// Send piss bucket animation // Send piss bucket animation
VisualUpdateMessage vum = new VisualUpdateMessage(player, 16323); VisualUpdateMessage vum = new VisualUpdateMessage(player, 16323);
vum.configure(); vum.configure();
DispatchMessage.sendToAllInRange(player, vum); DispatchMessage.sendToAllInRange(player, vum);

96
src/engine/net/client/msg/ApplyRuneMsg.java

@ -10,6 +10,7 @@
package engine.net.client.msg; package engine.net.client.msg;
import engine.Enum; import engine.Enum;
import engine.gameManager.ChatManager;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.net.*; import engine.net.*;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
@ -70,18 +71,16 @@ public class ApplyRuneMsg extends ClientNetMsg {
} }
public static boolean applyRune(int runeID, ClientConnection origin, PlayerCharacter playerCharacter) { public static boolean applyRune(int runeID, ClientConnection origin, PlayerCharacter playerCharacter) {
RuneBase rb = RuneBase.getRuneBase(runeID); RuneBase rb = RuneBase.getRuneBase(runeID);
Dispatch dispatch; Dispatch dispatch;
if (playerCharacter == null || origin == null || rb == null) { if (playerCharacter == null || origin == null || rb == null) {
return false; return false;
} }
int raceID = playerCharacter.getRaceID();
//Check race is met //Check race is met
ConcurrentHashMap<Integer, Boolean> races = rb.getRace(); ConcurrentHashMap<Integer, Boolean> races = rb.getRace();
if(runeID != 3007 && runeID != 3014) {//bounty hunter and huntsman
if (races.size() > 0) { if (races.size() > 0) {
int raceID = playerCharacter.getRaceID();
boolean valid = false; boolean valid = false;
for (int validID : races.keySet()) { for (int validID : races.keySet()) {
if (validID == raceID) { if (validID == raceID) {
@ -89,11 +88,18 @@ public class ApplyRuneMsg extends ClientNetMsg {
break; break;
} }
} }
if(runeID == 3040)
valid = true;
if(runeID == 2514 && raceID == 1999)
valid = true;
if(runeID == 3036 && raceID == 1999)
valid = true;
if(runeID == 3033 && raceID == 1999)
valid = true;
if (!valid) { if (!valid) {
return false; return false;
} }
} }
//Check base class is met //Check base class is met
ConcurrentHashMap<Integer, Boolean> baseClasses = rb.getBaseClass(); ConcurrentHashMap<Integer, Boolean> baseClasses = rb.getBaseClass();
if (baseClasses.size() > 0) { if (baseClasses.size() > 0) {
@ -105,11 +111,18 @@ public class ApplyRuneMsg extends ClientNetMsg {
break; break;
} }
} }
if(runeID == 3040)
valid = true;
if(runeID == 3036 && raceID == 1999)
valid = true;
if(runeID == 3033 && raceID == 1999)
valid = true;
if(runeID == 3035 && baseClassID == 2501)
valid = true;
if (!valid) { if (!valid) {
return false; return false;
} }
} }
//Check promotion class is met //Check promotion class is met
ConcurrentHashMap<Integer, Boolean> promotionClasses = rb.getPromotionClass(); ConcurrentHashMap<Integer, Boolean> promotionClasses = rb.getPromotionClass();
if (promotionClasses.size() > 0) { if (promotionClasses.size() > 0) {
@ -121,11 +134,23 @@ public class ApplyRuneMsg extends ClientNetMsg {
break; break;
} }
} }
if(runeID == 3040)
valid = true;
if(runeID == 3004 && (playerCharacter.getPromotionClassID() == 2505 || playerCharacter.getPromotionClassID() == 2510))
valid = true;
if(runeID == 3036 && raceID == 1999)
valid = true;
if(runeID == 3033 && raceID == 1999)
valid = true;
if (!valid) { if (!valid) {
return false; return false;
} }
} }
} else{
if(playerCharacter.getPromotionClassID() == 2519){//priest
return false;
}
}
//Check disciplines are met //Check disciplines are met
ArrayList<CharacterRune> runes = playerCharacter.getRunes(); ArrayList<CharacterRune> runes = playerCharacter.getRunes();
ConcurrentHashMap<Integer, Boolean> disciplines = rb.getDiscipline(); ConcurrentHashMap<Integer, Boolean> disciplines = rb.getDiscipline();
@ -139,7 +164,6 @@ public class ApplyRuneMsg extends ClientNetMsg {
} }
} }
} }
int discCount = 0; int discCount = 0;
for (CharacterRune cr : runes) { for (CharacterRune cr : runes) {
int runeBaseID = cr.getRuneBaseID(); int runeBaseID = cr.getRuneBaseID();
@ -152,28 +176,32 @@ public class ApplyRuneMsg extends ClientNetMsg {
return false; return false;
} }
} }
//Check level is met //Check level is met
if (playerCharacter.getLevel() < rb.getLevelRequired()) { if (playerCharacter.getLevel() < rb.getLevelRequired()) {
return false; return false;
} }
int strTotal = 0; int strTotal = 0;
int dexTotal = 0; int dexTotal = 0;
int conTotal = 0; int conTotal = 0;
int intTotal = 0; int intTotal = 0;
int spiTotal = 0; int spiTotal = 0;
int cost = 0; int cost = 0;
//Check any attributes are met //Check any attributes are met
ArrayList<RuneBaseAttribute> attrs = rb.getAttrs(); ArrayList<RuneBaseAttribute> attrs = rb.getAttrs();
if (rb.getAttrs() != null) if (rb.getAttrs() != null)
for (RuneBaseAttribute rba : attrs) { for (RuneBaseAttribute rba : attrs) {
int attrID = rba.getAttributeID(); int attrID = rba.getAttributeID();
int mod = rba.getModValue(); int mod = rba.getModValue();
switch (attrID) { switch (attrID) {
case MBServerStatics.RUNE_COST_ATTRIBUTE_ID: case MBServerStatics.RUNE_COST_ATTRIBUTE_ID:
switch (rb.getName()) {
case "Born of the Ethyri":
case "Born of the Taripontor":
case "Born of the Gwendannen":
case "Born of the Invorri":
case "Born of the Irydnu":
mod = 0;
}
if (mod > playerCharacter.getUnusedStatPoints()) { if (mod > playerCharacter.getUnusedStatPoints()) {
return false; return false;
} }
@ -226,14 +254,33 @@ public class ApplyRuneMsg extends ClientNetMsg {
break; break;
} }
} }
//Check if max number runes already reached //Check if max number runes already reached
if (runes.size() > 12) { if (runes.size() > 12) {
return false; return false;
} }
switch (rb.getName()) {
case "Born of the Ethyri":
case "Born of the Taripontor":
case "Born of the Gwendannen":
case "Born of the Invorri":
case "Born of the Irydnu":
for (CharacterRune charRune : playerCharacter.getRunes()) {
RuneBase rb2 = charRune.getRuneBase();
switch (rb2.getName()) {
case "Born of the Ethyri":
case "Born of the Taripontor":
case "Born of the Gwendannen":
case "Born of the Invorri":
case "Born of the Irydnu":
ChatManager.chatSystemError(playerCharacter, "You Have Already Applied A Blood Rune");
return false;
}
}
}
//if discipline, check number applied //if discipline, check number applied
if (isDiscipline(runeID)) { if (isDiscipline(runeID)) {
//if(playerCharacter.getLevel() == 80)
discCount -= 1; // level 80 characters get an extra disc rune
if (playerCharacter.getLevel() < 70) { if (playerCharacter.getLevel() < 70) {
if (discCount > 2) { if (discCount > 2) {
return false; return false;
@ -244,7 +291,6 @@ public class ApplyRuneMsg extends ClientNetMsg {
} }
} }
} }
//Everything succeeded. Let's apply the rune //Everything succeeded. Let's apply the rune
//Attempt add rune to database //Attempt add rune to database
CharacterRune runeWithoutID = new CharacterRune(rb, playerCharacter.getObjectUUID()); CharacterRune runeWithoutID = new CharacterRune(rb, playerCharacter.getObjectUUID());
@ -258,7 +304,6 @@ public class ApplyRuneMsg extends ClientNetMsg {
if (cr == null) { if (cr == null) {
return false; return false;
} }
//remove any overridden runes from player //remove any overridden runes from player
ArrayList<Integer> overwrite = rb.getOverwrite(); ArrayList<Integer> overwrite = rb.getOverwrite();
CharacterRune toRemove = null; CharacterRune toRemove = null;
@ -267,13 +312,10 @@ public class ApplyRuneMsg extends ClientNetMsg {
toRemove = playerCharacter.removeRune(overwriteID); toRemove = playerCharacter.removeRune(overwriteID);
} }
} }
//add rune to player //add rune to player
playerCharacter.addRune(cr); playerCharacter.addRune(cr);
// recalculate all bonuses/formulas/skills/powers // recalculate all bonuses/formulas/skills/powers
playerCharacter.recalculate(); playerCharacter.recalculate();
//if overwriting a stat rune, add any amount granted from previous rune. //if overwriting a stat rune, add any amount granted from previous rune.
if (toRemove != null) { if (toRemove != null) {
RuneBase rbs = toRemove.getRuneBase(); RuneBase rbs = toRemove.getRuneBase();
@ -299,30 +341,32 @@ public class ApplyRuneMsg extends ClientNetMsg {
if (dif > 0 && spiTotal < (int) playerCharacter.statSpiMax) { if (dif > 0 && spiTotal < (int) playerCharacter.statSpiMax) {
playerCharacter.addSpi(dif); playerCharacter.addSpi(dif);
} }
// recalculate all bonuses/formulas/skills/powers // recalculate all bonuses/formulas/skills/powers
playerCharacter.recalculate(); playerCharacter.recalculate();
} }
} }
switch (rb.getName()) {
case "Born of the Ethyri":
case "Born of the Taripontor":
case "Born of the Gwendannen":
case "Born of the Invorri":
case "Born of the Irydnu":
cost = 0;
break;
}
if (cost > 0) { if (cost > 0) {
ModifyStatMsg msm = new ModifyStatMsg((0 - cost), 0, 3); ModifyStatMsg msm = new ModifyStatMsg((0 - cost), 0, 3);
dispatch = Dispatch.borrow(playerCharacter, msm); dispatch = Dispatch.borrow(playerCharacter, msm);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
} }
//send apply rune message to client //send apply rune message to client
ApplyRuneMsg arm = new ApplyRuneMsg(playerCharacter.getObjectType().ordinal(), playerCharacter.getObjectUUID(), runeID, cr.getObjectType().ordinal(), cr.getObjectUUID(), false); ApplyRuneMsg arm = new ApplyRuneMsg(playerCharacter.getObjectType().ordinal(), playerCharacter.getObjectUUID(), runeID, cr.getObjectType().ordinal(), cr.getObjectUUID(), false);
dispatch = Dispatch.borrow(playerCharacter, arm); dispatch = Dispatch.borrow(playerCharacter, arm);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
//alert them of success //alert them of success
ErrorPopupMsg.sendErrorPopup(playerCharacter, 160); ErrorPopupMsg.sendErrorPopup(playerCharacter, 160);
//reapply bonuses //reapply bonuses
playerCharacter.applyBonuses(); playerCharacter.applyBonuses();
return true; return true;
} }

8
src/engine/net/client/msg/CityDataMsg.java

@ -104,8 +104,10 @@ public class CityDataMsg extends ClientNetMsg {
} }
temp.putInt(mineList.size()); temp.putInt(mineList.size());
for (Mine mine : mineList) for (Mine mine : mineList) {
if(mine.getParentZone() != null && !mine.getParentZone().isContinent())
Mine.serializeForClientMsg(mine, temp); Mine.serializeForClientMsg(mine, temp);
}
temp.put((byte) 0); // PAD temp.put((byte) 0); // PAD
} }
@ -178,8 +180,10 @@ public class CityDataMsg extends ClientNetMsg {
} }
writer.putInt(mineList.size()); writer.putInt(mineList.size());
for (Mine mine : mineList) for (Mine mine : mineList) {
if(mine.getParentZone() != null && !mine.getParentZone().isContinent())
Mine.serializeForClientMsg(mine, writer); Mine.serializeForClientMsg(mine, writer);
}
} else } else
writer.putInt(0); writer.putInt(0);
} catch (Exception e) { } catch (Exception e) {

6
src/engine/net/client/msg/ManageCityAssetsMsg.java

@ -275,7 +275,7 @@ public class ManageCityAssetsMsg extends ClientNetMsg {
writer.putString(npcHire.getName()); writer.putString(npcHire.getName());
writer.putInt(1); writer.putInt(1);
writer.putInt(Blueprint.getNpcMaintCost(npcHire.getRank())); writer.putInt(0);
if (npcHire.getObjectType() == GameObjectType.NPC) if (npcHire.getObjectType() == GameObjectType.NPC)
writer.putInt(((NPC) npcHire).getContract().getIconID()); // Was 60 writer.putInt(((NPC) npcHire).getContract().getIconID()); // Was 60
else if (npcHire.getObjectType() == GameObjectType.Mob) { else if (npcHire.getObjectType() == GameObjectType.Mob) {
@ -497,7 +497,7 @@ public class ManageCityAssetsMsg extends ClientNetMsg {
if (building.getBlueprint() == null) if (building.getBlueprint() == null)
writer.putInt(0); writer.putInt(0);
else else
writer.putInt(building.getBlueprint().getMaintCost(building.getRank())); // maint cost writer.putInt(building.getBlueprint().getMaintCost()); // maint cost
if (building.getRank() == 8) { if (building.getRank() == 8) {
writer.putInt(74856115); // Stone writer.putInt(74856115); // Stone
@ -514,7 +514,7 @@ public class ManageCityAssetsMsg extends ClientNetMsg {
if (maintDate == null) if (maintDate == null)
maintDate = LocalDateTime.now(); maintDate = LocalDateTime.now();
writer.putLocalDateTime(LocalDateTime.now()); // current time writer.putLocalDateTime(maintDate); // current time
// utc offset? // utc offset?
writer.putInt((int) java.time.Duration.between(LocalDateTime.now(), maintDate).getSeconds()); // Seconds to maint date writer.putInt((int) java.time.Duration.between(LocalDateTime.now(), maintDate).getSeconds()); // Seconds to maint date

40
src/engine/net/client/msg/ServerInfoMsg.java

@ -11,6 +11,7 @@ package engine.net.client.msg;
import engine.gameManager.ConfigManager; import engine.gameManager.ConfigManager;
import engine.gameManager.DbManager;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
@ -53,18 +54,45 @@ public class ServerInfoMsg extends ClientNetMsg {
writer.putInt(WorldServer.worldMapID); writer.putInt(WorldServer.worldMapID);
writer.putString(ConfigManager.MB_WORLD_NAME.getValue()); writer.putString(ConfigManager.MB_WORLD_NAME.getValue());
if (LoginServer.population < MBServerStatics.LOW_POPULATION) int TotalTrees = 21;
int currentR8Trees = DbManager.CityQueries.GET_CAPITAL_CITY_COUNT();
switch(currentR8Trees){
case 0:
case 1:
case 2:
case 3:
case 4:
writer.putInt(0); //Land Rush writer.putInt(0); //Land Rush
else if (LoginServer.population < MBServerStatics.NORMAL_POPULATION) break;
case 5:
case 6:
case 7:
case 8:
writer.putInt(1); //Low pop writer.putInt(1); //Low pop
else if (LoginServer.population < MBServerStatics.HIGH_POPULATION) break;
case 9:
case 10:
case 11:
case 12:
writer.putInt(2); //Normal pop writer.putInt(2); //Normal pop
else if (LoginServer.population < MBServerStatics.VERY_OVERPOPULATED_POPULATION) break;
case 13:
case 14:
case 15:
case 16:
writer.putInt(3); //High Pop writer.putInt(3); //High Pop
else if (LoginServer.population < MBServerStatics.FULL_POPULATION) break;
case 17:
case 18:
case 19:
case 20:
writer.putInt(4); //Very overpopulated pop writer.putInt(4); //Very overpopulated pop
else break;
default:
writer.putInt(5); //Full pop writer.putInt(5); //Full pop
break;
}
} }
/** /**

5
src/engine/net/client/msg/VendorDialogMsg.java

@ -96,6 +96,11 @@ public class VendorDialogMsg extends ClientNetMsg {
return; return;
} }
if(npc.contractUUID == 1502040){ //enrollment officer
PlayerCharacter.unboxPlayer(playerCharacter);
}
// Restrict disc trainers to only characters who have // Restrict disc trainers to only characters who have
// tht disc applied. // tht disc applied.

33
src/engine/objects/AbstractCharacter.java

@ -1187,10 +1187,15 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
} }
} }
public final float modifyHealth( public final float modifyHealth(float value, final AbstractCharacter attacker, final boolean fromCost) {
final float value,
final AbstractCharacter attacker, if(attacker != null && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)){
final boolean fromCost) { value *= ((PlayerCharacter)attacker).ZergMultiplier;
} // Health modifications are modified by the ZergMechanic
if(attacker != null && attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob)attacker).getOwner() != null){
value *= ((Mob)attacker).getOwner().ZergMultiplier;
}// Health modifications from pets are modified by the owner's ZergMechanic
try { try {
@ -1254,11 +1259,19 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
} }
public final float modifyMana( public final float modifyMana(
final float value, float value,
final AbstractCharacter attacker, final AbstractCharacter attacker,
final boolean fromCost final boolean fromCost
) { ) {
if(attacker != null && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)){
value *= ((PlayerCharacter)attacker).ZergMultiplier;
} // Health modifications are modified by the ZergMechanic
if(attacker != null && attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob)attacker).getOwner() != null){
value *= ((Mob)attacker).getOwner().ZergMultiplier;
}// Health modifications from pets are modified by the owner's ZergMechanic
if (!this.isAlive()) { if (!this.isAlive()) {
return 0f; return 0f;
} }
@ -1293,11 +1306,19 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
} }
public final float modifyStamina( public final float modifyStamina(
final float value, float value,
final AbstractCharacter attacker, final AbstractCharacter attacker,
final boolean fromCost final boolean fromCost
) { ) {
if(attacker != null && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)){
value *= ((PlayerCharacter)attacker).ZergMultiplier;
} // Health modifications are modified by the ZergMechanic
if(attacker != null && attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob)attacker).getOwner() != null){
value *= ((Mob)attacker).getOwner().ZergMultiplier;
}// Health modifications from pets are modified by the owner's ZergMechanic
if (!this.isAlive()) { if (!this.isAlive()) {
return 0f; return 0f;
} }

46
src/engine/objects/Blueprint.java

@ -108,9 +108,11 @@ public class Blueprint {
maxShrines = 2; maxShrines = 2;
break; break;
case 7: case 7:
case 8:
maxShrines = 3; maxShrines = 3;
break; break;
case 8:
maxShrines = 4;
break;
default: default:
maxShrines = 0; maxShrines = 0;
@ -167,11 +169,7 @@ public class Blueprint {
// based upon the building's current rank // based upon the building's current rank
public static int getNpcMaintCost(int rank) { public static int getNpcMaintCost(int rank) {
int maintCost = Integer.MAX_VALUE; return 0;
maintCost = (9730 * rank) + 1890;
return maintCost;
} }
public int getMaxRank() { public int getMaxRank() {
@ -181,6 +179,8 @@ public class Blueprint {
public int getMaxSlots() { public int getMaxSlots() {
if (this.buildingGroup != null && this.buildingGroup.equals(BuildingGroup.BARRACK)) if (this.buildingGroup != null && this.buildingGroup.equals(BuildingGroup.BARRACK))
return 1; return 1;
if (this.buildingGroup != null && this.buildingGroup.equals(BuildingGroup.TOL))
return 4;
return maxSlots; return maxSlots;
} }
@ -313,7 +313,7 @@ public class Blueprint {
// Early exit for buildings with single or no slots // Early exit for buildings with single or no slots
if (this.maxSlots <= 1) if (this.maxSlots <= 1 && !this.buildingGroup.equals(BuildingGroup.TOL))
return maxSlots; return maxSlots;
if (this.maxRank == 1 && currentRank == 1) if (this.maxRank == 1 && currentRank == 1)
@ -327,20 +327,20 @@ public class Blueprint {
break; break;
case 3: case 3:
case 4: case 4:
case 5:
case 6:
availableSlots = 2; availableSlots = 2;
break; break;
case 5:
case 6:
case 7: case 7:
availableSlots = 3;
break;
case 8: case 8:
availableSlots = 1; availableSlots = 3;
break; break;
default: default:
availableSlots = 0; availableSlots = 0;
break; break;
} }
if(this.buildingGroup != null && this.buildingGroup.equals(BuildingGroup.TOL))
availableSlots += 1;
return availableSlots; return availableSlots;
} }
@ -603,26 +603,14 @@ public class Blueprint {
return this.blueprintUUID; return this.blueprintUUID;
} }
public int getMaintCost(int rank) { public int getMaintCost() {
int maintCost = Integer.MAX_VALUE; int maintCost = Integer.MAX_VALUE;
switch (this.buildingGroup) { if(this.buildingGroup.equals(BuildingGroup.TOL)){
case TOL: return 3000000;
case BARRACK: }else{
maintCost = (61500 * rank) + 19500; return 0;
break;
case SPIRE:
maintCost = (4800 * rank) + 1200;
break;
default:
if (maxRank == 1)
maintCost = 22500;
else
maintCost = (15900 * rank) + 3300;
break;
} }
return maintCost;
} }
} }

21
src/engine/objects/Building.java

@ -780,24 +780,9 @@ public class Building extends AbstractWorldObject {
public int getMaintCost() { public int getMaintCost() {
int maintCost = 0; if(this.getBlueprint() != null && this.getBlueprint().getBuildingGroup().equals(BuildingGroup.TOL))
return 3000000;
// Add cost for building structure else return 0;
maintCost += this.getBlueprint().getMaintCost(rank);
// Add costs associated with hirelings
for (AbstractCharacter npc : this.hirelings.keySet()) {
if (npc.getObjectType() != GameObjectType.NPC)
continue;
maintCost += Blueprint.getNpcMaintCost(npc.getRank());
}
return maintCost;
} }
public final void submitOpenDoorJob(int doorID) { public final void submitOpenDoorJob(int doorID) {

91
src/engine/objects/Contract.java

@ -86,6 +86,12 @@ public class Contract extends AbstractGameObject {
this.iconID = rs.getInt("iconID"); this.iconID = rs.getInt("iconID");
this.vendorID = rs.getInt("vendorID"); this.vendorID = rs.getInt("vendorID");
this.allowedBuildings = EnumBitSet.asEnumBitSet(rs.getLong("allowedBuildingTypeID"), Enum.BuildingGroup.class); this.allowedBuildings = EnumBitSet.asEnumBitSet(rs.getLong("allowedBuildingTypeID"), Enum.BuildingGroup.class);
switch(this.contractID){
case 866: //banker
case 865: //siege engineer
case 899: //alchemist
this.allowedBuildings.add(Enum.BuildingGroup.TOL);
}
this.equipmentSet = rs.getInt("equipSetID"); this.equipmentSet = rs.getInt("equipSetID");
this.inventorySet = rs.getInt("inventorySet"); this.inventorySet = rs.getInt("inventorySet");
@ -198,6 +204,91 @@ public class Contract extends AbstractGameObject {
} }
public ArrayList<MobEquipment> getSellInventory() { public ArrayList<MobEquipment> getSellInventory() {
if(this.getObjectUUID() == 900){ //resource merchant
for(MobEquipment me : this.sellInventory){
if(me.getItemBase().getType().equals(Enum.ItemType.RESOURCE)){
int amountResource = Warehouse.getSellStackSize(me.getItemBase().getUUID());
me.magicValue = amountResource * me.getItemBase().getBaseValue() * 2;
} else{
me.magicValue = 100000;
}
}
}
if(this.getObjectUUID() == 1202){ //rune merchant
for(MobEquipment me : this.sellInventory){
switch(me.getItemBase().getUUID()){
case 250001: //5 stats
case 250010:
case 250019:
case 250028:
case 250037:
me.magicValue = 3000000;
break;
case 250002: //10 stats
case 250011:
case 250020:
case 250029:
case 250038:
me.magicValue = 4000000;
break;
case 250003: //15 stats
case 250012:
case 250021:
case 250030:
case 250039:
me.magicValue = 5000000;
break;
case 250004: //20 stats
case 250013:
case 250022:
case 250031:
case 250040:
me.magicValue = 6000000;
break;
case 250005: //25 stats
case 250014:
case 250023:
case 250032:
case 250041:
me.magicValue = 7000000;
break;
case 250006: //30 stats
case 250015:
case 250024:
case 250033:
case 250042:
me.magicValue = 8000000;
break;
case 250007: //35 stats
case 250016:
case 250025:
case 250034:
case 250043:
me.magicValue = 9000000;
break;
default:
me.magicValue = 10000000;
break;
}
}
}
if(this.getObjectUUID() == 1201){ //disc merchant
for(MobEquipment me : this.sellInventory){
if(me.getItemBase().getName().equals("Prospector")){
me.magicValue = 500000;
}else{
me.magicValue = 10000000;
}
}
}
if(this.getObjectUUID() == 1502041) {//noob helper{
for(MobEquipment me : this.sellInventory){
me.magicValue = 1;
}
}
return this.sellInventory; return this.sellInventory;
} }

6
src/engine/objects/Guild.java

@ -752,9 +752,9 @@ public class Guild extends AbstractWorldObject {
canSub = false; canSub = false;
} }
City nationCap = City.getCity(nation.cityUUID); City nationCap = City.getCity(nation.cityUUID);
if (nation.getSubGuildList().size() >= nationCap.getRank()) { //if (nation.getSubGuildList().size() >= nationCap.getRank()) {
canSub = false; // canSub = false;
} //}
return canSub; return canSub;
} }

17
src/engine/objects/Item.java

@ -233,7 +233,6 @@ public class Item extends AbstractWorldObject {
this.value = rs.getInt("item_value"); this.value = rs.getInt("item_value");
this.customName = rs.getString("item_name"); this.customName = rs.getString("item_name");
} }
public static void _serializeForClientMsg(Item item, ByteBufferWriter writer) public static void _serializeForClientMsg(Item item, ByteBufferWriter writer)
@ -303,7 +302,7 @@ public class Item extends AbstractWorldObject {
writer.putString(item.customName); // Unknown. pad? writer.putString(item.customName); // Unknown. pad?
writer.put((byte) 1); // End Datablock byte writer.put((byte) 1); // End Datablock byte
writer.putFloat((float) item.durabilityMax); writer.putFloat((float) item.getDurabilityMax());
writer.putFloat((float) item.durabilityCurrent); writer.putFloat((float) item.durabilityCurrent);
writer.put((byte) 1); // End Datablock byte writer.put((byte) 1); // End Datablock byte
@ -609,7 +608,7 @@ public class Item extends AbstractWorldObject {
writer.putIntAt(serialized, indexPosition); writer.putIntAt(serialized, indexPosition);
} }
public static Item createItemForPlayer(PlayerCharacter pc, ItemBase ib) { public static Item createItemForPlayer(PlayerCharacter pc, ItemBase ib, boolean fromNoob) {
Item item = null; Item item = null;
byte charges = 0; byte charges = 0;
@ -885,7 +884,15 @@ public class Item extends AbstractWorldObject {
} }
public short getDurabilityMax() { public short getDurabilityMax() {
return durabilityMax; int extra = 0;
for(Effect eff : this.effects.values()){
for(AbstractEffectModifier mod : eff.getEffectModifiers()){
if(mod.modType.equals(ModType.Durability)){
extra += mod.getMaxMod();
}
}
}
return (short)(durabilityMax + extra);
} }
public boolean isCanDestroy() { public boolean isCanDestroy() {
@ -948,6 +955,7 @@ public class Item extends AbstractWorldObject {
} }
public boolean isID() { public boolean isID() {
this.flags |= 1;
return ((this.flags & 1) > 0); return ((this.flags & 1) > 0);
} }
@ -1197,6 +1205,7 @@ public class Item extends AbstractWorldObject {
} }
public int getBaseValue() { public int getBaseValue() {
if (this.getItemBase() != null) if (this.getItemBase() != null)
return this.getItemBase().getBaseValue(); return this.getItemBase().getBaseValue();
return 0; return 0;

151
src/engine/objects/ItemBase.java

@ -75,7 +75,6 @@ public class ItemBase {
private boolean isStrBased; private boolean isStrBased;
private ArrayList<Integer> animations = new ArrayList<>(); private ArrayList<Integer> animations = new ArrayList<>();
private ArrayList<Integer> offHandAnimations = new ArrayList<>(); private ArrayList<Integer> offHandAnimations = new ArrayList<>();
private boolean autoID = false;
/** /**
* ResultSet Constructor * ResultSet Constructor
@ -145,8 +144,6 @@ public class ItemBase {
} }
this.autoIDItemsCheck();
try { try {
DbManager.ItemBaseQueries.LOAD_ANIMATIONS(this); DbManager.ItemBaseQueries.LOAD_ANIMATIONS(this);
} catch (Exception e) { } catch (Exception e) {
@ -223,16 +220,76 @@ public class ItemBase {
AnniverseryGifts.add(971008); AnniverseryGifts.add(971008);
AnniverseryGifts.add(971009); AnniverseryGifts.add(971009);
AnniverseryGifts.add(971010); AnniverseryGifts.add(971010);
AnniverseryGifts.add(5101000); //AnniverseryGifts.add(5101000);
AnniverseryGifts.add(5101020); //AnniverseryGifts.add(5101020);
AnniverseryGifts.add(5101100); //AnniverseryGifts.add(5101100);
AnniverseryGifts.add(5101120); //AnniverseryGifts.add(5101120);
AnniverseryGifts.add(5101040); //AnniverseryGifts.add(5101040);
AnniverseryGifts.add(5101140); //AnniverseryGifts.add(5101140);
AnniverseryGifts.add(5101060); //AnniverseryGifts.add(5101060);
AnniverseryGifts.add(5101080); //AnniverseryGifts.add(5101080);
}
public static int getDiscPrice(int uuid) {
if(uuid == 3040)
return 500000;
else return 10000000;
}
public static int getStatPrice(int uuid) {
switch(uuid){
case 250001: //5 stats
case 250010:
case 250019:
case 250028:
case 250037:
return 3000000;
case 250002: //10 stats
case 250011:
case 250020:
case 250029:
case 250038:
return 4000000;
case 250003: //15 stats
case 250012:
case 250021:
case 250030:
case 250039:
return 5000000;
case 250004: //20 stats
case 250013:
case 250022:
case 250031:
case 250040:
return 6000000;
case 250005: //25 stats
case 250014:
case 250023:
case 250032:
case 250041:
return 7000000;
case 250006: //30 stats
case 250015:
case 250024:
case 250033:
case 250042:
return 8000000;
case 250007: //35 stats
case 250016:
case 250025:
case 250034:
case 250043:
return 9000000;
case 250008: //40 stats
case 250017:
case 250026:
case 250035:
case 250044:
return 10000000;
}
return 10000000;
} }
/* /*
@ -372,74 +429,10 @@ public class ItemBase {
return modTable; return modTable;
} }
public int getVendorType() {
return vendorType;
}
public void setVendorType(int vendorType) {
this.vendorType = vendorType;
}
public int getHashID() { public int getHashID() {
return hashID; return hashID;
} }
public void setHashID(int hashID) {
this.hashID = hashID;
}
private void autoIDItemsCheck() {
//AUto ID Vorg and Glass
switch (uuid) {
case 27550:
case 27560:
case 27580:
case 27590:
case 188500:
case 188510:
case 188520:
case 188530:
case 188540:
case 188550:
case 189100:
case 189110:
case 189120:
case 189130:
case 189140:
case 189150:
case 189510:
case 27600:
case 181840:
case 188700:
case 188720:
case 189550:
case 189560:
case 7000100:
case 7000110:
case 7000120:
case 7000130:
case 7000140:
case 7000150:
case 7000160:
case 7000170:
case 7000180:
case 7000190:
case 7000200:
case 7000210:
case 7000220:
case 7000230:
case 7000240:
case 7000250:
case 7000270:
case 7000280:
this.autoID = true;
break;
default:
this.autoID = false;
}
}
public boolean validForSkills(ConcurrentHashMap<String, CharacterSkill> skills) { public boolean validForSkills(ConcurrentHashMap<String, CharacterSkill> skills) {
CharacterSkill characterSkill; CharacterSkill characterSkill;
@ -906,12 +899,4 @@ public class ItemBase {
public void setOffHandAnimations(ArrayList<Integer> offHandAnimations) { public void setOffHandAnimations(ArrayList<Integer> offHandAnimations) {
this.offHandAnimations = offHandAnimations; this.offHandAnimations = offHandAnimations;
} }
public boolean isAutoID() {
return autoID;
}
public void setAutoID(boolean autoID) {
this.autoID = autoID;
}
} }

216
src/engine/objects/Mine.java

@ -11,10 +11,7 @@ package engine.objects;
import engine.Enum; import engine.Enum;
import engine.InterestManagement.WorldGrid; import engine.InterestManagement.WorldGrid;
import engine.gameManager.BuildingManager; import engine.gameManager.*;
import engine.gameManager.ChatManager;
import engine.gameManager.DbManager;
import engine.gameManager.ZoneManager;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.msg.ErrorPopupMsg; import engine.net.client.msg.ErrorPopupMsg;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
@ -25,6 +22,9 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import static engine.gameManager.DbManager.MineQueries; import static engine.gameManager.DbManager.MineQueries;
@ -51,6 +51,13 @@ public class Mine extends AbstractGameObject {
private int buildingID; private int buildingID;
private MineProduction mineType; private MineProduction mineType;
public int openHour;
public int openMinute;
public int capSize;
public LocalDateTime liveTime;
public final HashSet<Integer> _playerMemory = new HashSet<>();
public ArrayList<PlayerCharacter> affectedPlayers = new ArrayList<>();
/** /**
* ResultSet Constructor * ResultSet Constructor
*/ */
@ -90,7 +97,15 @@ public class Mine extends AbstractGameObject {
this.production = Resource.valueOf(rs.getString("mine_resource")); this.production = Resource.valueOf(rs.getString("mine_resource"));
this.lastClaimer = null; this.lastClaimer = null;
this.openHour = rs.getInt("mineLiveHour");
this.openMinute = rs.getInt("mineLiveMinute");
this.capSize = rs.getInt("capSize");
this.liveTime = LocalDateTime.now().withHour(this.openHour).withMinute(this.openMinute);
Building tower = BuildingManager.getBuildingFromCache(this.buildingID);
if(tower != null){
tower.setMaxHitPoints(5000f * this.capSize);
tower.setCurrentHitPoints(tower.healthMax);
}
} }
public static void releaseMineClaims(PlayerCharacter playerCharacter) { public static void releaseMineClaims(PlayerCharacter playerCharacter) {
@ -161,49 +176,35 @@ public class Mine extends AbstractGameObject {
} }
public static void serializeForClientMsg(Mine mine, ByteBufferWriter writer) { public static void serializeForClientMsg(Mine mine, ByteBufferWriter writer) {
try {
writer.putInt(mine.getObjectType().ordinal()); writer.putInt(mine.getObjectType().ordinal());
writer.putInt(mine.getObjectUUID()); writer.putInt(mine.getObjectUUID());
writer.putInt(mine.getObjectUUID()); //actually a hash of mine writer.putInt(mine.getObjectUUID()); //actually a hash of mine
writer.putString(mine.mineType.name); writer.putString(mine.mineType.name);
writer.putString(mine.zoneName); //writer.putString(mine.zoneName + " " + mine.capSize + " Man ");
writer.putString(mine.capSize + " Man ");
writer.putInt(mine.production.hash); writer.putInt(mine.production.hash);
writer.putInt(mine.production.baseProduction); writer.putInt(mine.production.baseProduction);
writer.putInt(mine.getModifiedProductionAmount()); //TODO calculate range penalty here writer.putInt(mine.getModifiedProductionAmount()); //TODO calculate range penalty here
writer.putInt(3600); //window in seconds writer.putInt(3600); //window in seconds
// Errant mines are currently open. Set time to now. LocalDateTime mineOpenTime = LocalDateTime.now().withHour(mine.openHour).withMinute(mine.openMinute).withSecond(0).withNano(0);
LocalDateTime mineOpenTime = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0);
// Mine times are those of the nation not individual guild.
Guild mineNatonGuild = mine.getOwningGuild().getNation();
// Adjust the serialized mine time based upon whether
// the Guild's mine window has passed or not and if it was claimed.
// If a mine is active serialize current datetime irrespective
// of any claim.
if (mineNatonGuild.isEmptyGuild() == false && mine.isActive == false) {
int guildWOO = mineNatonGuild.getNation().getMineTime();
LocalDateTime guildMineTime = mineOpenTime.withHour(guildWOO);
if (mineOpenTime.isAfter(guildMineTime) || mine.wasClaimed == true)
mineOpenTime = guildMineTime.plusDays(1);
else
mineOpenTime = guildMineTime;
}
writer.putLocalDateTime(mineOpenTime); writer.putLocalDateTime(mineOpenTime);
writer.putLocalDateTime(mineOpenTime.plusHours(1)); writer.putLocalDateTime(mineOpenTime.plusMinutes(30));
writer.put(mine.isActive ? (byte) 0x01 : (byte) 0x00); writer.put(mine.isActive ? (byte) 0x01 : (byte) 0x00);
Building mineTower = BuildingManager.getBuilding(mine.buildingID); Building mineTower = BuildingManager.getBuilding(mine.buildingID);
if (mineTower != null) {
writer.putFloat(mineTower.getLoc().x); writer.putFloat(mineTower.getLoc().x);
writer.putFloat(mineTower.getParentZone().getLoc().y); writer.putFloat(mineTower.getParentZone().getLoc().y);
writer.putFloat(mineTower.getLoc().z); writer.putFloat(mineTower.getLoc().z);
} else {
writer.putFloat(mine.parentZone.getLoc().x);
writer.putFloat(mine.parentZone.getLoc().y);
writer.putFloat(mine.parentZone.getLoc().z);
Logger.error("Mine Tower Was Null For Mine: " + mine.getObjectUUID());
}
writer.putInt(mine.isExpansion() ? mine.mineType.xpacHash : mine.mineType.hash); writer.putInt(mine.isExpansion() ? mine.mineType.xpacHash : mine.mineType.hash);
@ -211,6 +212,9 @@ public class Mine extends AbstractGameObject {
GuildTag._serializeForDisplay(mine.guildTag, writer); GuildTag._serializeForDisplay(mine.guildTag, writer);
writer.putString(mine.nationName); writer.putString(mine.nationName);
GuildTag._serializeForDisplay(mine.nationTag, writer); GuildTag._serializeForDisplay(mine.nationTag, writer);
} catch (Exception e) {
Logger.error("Failed TO Serialize Mine Because: " + e.getMessage());
}
} }
public static ArrayList<Mine> getMinesForGuild(int guildID) { public static ArrayList<Mine> getMinesForGuild(int guildID) {
@ -290,26 +294,9 @@ public class Mine extends AbstractGameObject {
if (treeRank < 1) if (treeRank < 1)
return false; return false;
if (guildUnderMineLimit(playerGuild.getNation(), treeRank) == false) {
ErrorPopupMsg.sendErrorMsg(playerCharacter, "Your nation cannot support another mine.");
return false;
}
return true; return true;
} }
private static boolean guildUnderMineLimit(Guild playerGuild, int tolRank) {
int mineCnt = 0;
mineCnt += Mine.getMinesForGuild(playerGuild.getObjectUUID()).size();
for (Guild guild : playerGuild.getSubGuildList())
mineCnt += Mine.getMinesForGuild(guild.getObjectUUID()).size();
return mineCnt <= tolRank;
}
public boolean changeProductionType(Resource resource) { public boolean changeProductionType(Resource resource) {
if (!this.validForMine(resource)) if (!this.validForMine(resource))
return false; return false;
@ -378,6 +365,16 @@ public class Mine extends AbstractGameObject {
Building building = BuildingManager.getBuildingFromCache(this.buildingID); Building building = BuildingManager.getBuildingFromCache(this.buildingID);
if (building != null && !this.isActive) if (building != null && !this.isActive)
building.isDeranking.compareAndSet(true, false); building.isDeranking.compareAndSet(true, false);
if(!isAc){
for(PlayerCharacter player : this.affectedPlayers){
try {
player.ZergMultiplier = 1.0f;
} catch(Exception e){
//something went wrong resetting zerg multiplier, maybe player was deleted?
}
}
}
} }
public boolean validForMine(Resource r) { public boolean validForMine(Resource r) {
@ -538,41 +535,106 @@ public class Mine extends AbstractGameObject {
} }
public int getModifiedProductionAmount() { public int getModifiedProductionAmount() {
//TODO Calculate Distance modifications. ItemBase resourceBase = ItemBase.getItemBase(this.production.UUID);
if(resourceBase == null)
return 0;
int value = resourceBase.getBaseValue();
int amount = 0;
switch(this.capSize){
case 3:
amount = 1800000;
break;
case 5:
amount = 3000000;
break;
case 10:
amount = 6000000;
break;
case 20:
amount = 12000000;
break;
}
if(this.production.UUID == 7)
value = 1;
amount = amount / value;
return amount;
}
public void onEnter() {
Building tower = BuildingManager.getBuildingFromCache(this.buildingID);
if(tower == null)
return;
//calculate base values. // Gather current list of players within the zone bounds
int baseProduction = this.production.baseProduction;
float baseModValue = this.production.baseProduction * .1f;
float rankModValue = this.production.baseProduction * .0143f;
float totalModded = 0;
//get Mine Building. HashSet<AbstractWorldObject> currentPlayers = WorldGrid.getObjectsInRangePartial(tower.loc, Enum.CityBoundsType.GRID.extents, MBServerStatics.MASK_PLAYER);
Building mineBuilding = BuildingManager.getBuilding(this.buildingID); HashMap<Guild,ArrayList<PlayerCharacter>> charactersByNation = new HashMap<>();
if (mineBuilding == null) ArrayList<Guild> updatedNations = new ArrayList<>();
return this.production.baseProduction; for (AbstractWorldObject playerObject : currentPlayers) {
for (AbstractCharacter harvester : mineBuilding.getHirelings().keySet()) {
totalModded += baseModValue; if (playerObject == null)
totalModded += rankModValue * harvester.getRank(); continue;
}
//add base production on top;
totalModded += baseProduction;
//skip distance check for expansion.
if (this.isExpansion())
return (int) totalModded;
if (this.owningGuild.isEmptyGuild() == false) { PlayerCharacter player = (PlayerCharacter) playerObject;
if (this.owningGuild.getOwnedCity() != null) {
float distanceSquared = this.owningGuild.getOwnedCity().getLoc().distanceSquared2D(mineBuilding.getLoc());
if (distanceSquared > sqr(10000 * 3)) if(this.affectedPlayers.contains(player) == false)
totalModded *= .25f; this.affectedPlayers.add(player);
else if (distanceSquared > sqr(10000 * 2))
totalModded *= .50f; if(!this._playerMemory.contains(player.getObjectUUID())){
else if (distanceSquared > sqr(10000)) this._playerMemory.add(player.getObjectUUID());
totalModded *= .75f; }
Guild nation = player.guild.getNation();
if(charactersByNation.containsKey(nation)){
if(!charactersByNation.get(nation).contains(player)) {
charactersByNation.get(nation).add(player);
if(!updatedNations.contains(nation)){
updatedNations.add(nation);
}
}
}else{
ArrayList<PlayerCharacter> players = new ArrayList<>();
players.add(player);
charactersByNation.put(nation,players);
if(!updatedNations.contains(nation)){
updatedNations.add(nation);
} }
} }
return (int) totalModded;
} }
for(Guild nation : updatedNations){
float multiplier = ZergManager.getCurrentMultiplier(charactersByNation.get(nation).size(),this.capSize);
for(PlayerCharacter player : charactersByNation.get(nation)){
player.ZergMultiplier = multiplier;
}
}
try
{
this.onExit(this._playerMemory);
}
catch(Exception ignored){
}
}
private void onExit(HashSet<Integer> currentMemory) {
Building tower = BuildingManager.getBuildingFromCache(this.buildingID);
if(tower == null)
return;
ArrayList<Integer>toRemove = new ArrayList<>();
HashSet<AbstractWorldObject> currentPlayers = WorldGrid.getObjectsInRangePartial(tower.loc, Enum.CityBoundsType.GRID.extents, MBServerStatics.MASK_PLAYER);
for(Integer id : currentMemory){
PlayerCharacter pc = PlayerCharacter.getPlayerCharacter(id);
if(currentPlayers.contains(pc) == false){
toRemove.add(id);
pc.ZergMultiplier = 1.0f;
}
}
// Remove players from city memory
_playerMemory.removeAll(toRemove);
}
} }

18
src/engine/objects/Mob.java

@ -48,6 +48,7 @@ import static engine.net.client.msg.ErrorPopupMsg.sendErrorPopup;
public class Mob extends AbstractIntelligenceAgent { public class Mob extends AbstractIntelligenceAgent {
public static ArrayList<Mob> discDroppers = new ArrayList<>();
private static final ReentrantReadWriteLock createLock = new ReentrantReadWriteLock(); private static final ReentrantReadWriteLock createLock = new ReentrantReadWriteLock();
private static final ConcurrentHashMap<Integer, Mob> mobMapByDBID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); private static final ConcurrentHashMap<Integer, Mob> mobMapByDBID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
// Variables NOT to be stored in db // Variables NOT to be stored in db
@ -574,11 +575,11 @@ public class Mob extends AbstractIntelligenceAgent {
mob = new Mob(mobBase, guild, parent, level, owner, 0); mob = new Mob(mobBase, guild, parent, level, owner, 0);
if (mob.mobBase == null) if (mob.mobBase == null)
return null; return null;
mob.runAfterLoad();
Vector3fImmutable loc = owner.getLoc();
DbManager.addToCache(mob); DbManager.addToCache(mob);
mob.setPet(owner, true); mob.setPet(owner, true);
mob.setWalkMode(false); mob.setWalkMode(false);
mob.runAfterLoad();
} catch (Exception e) { } catch (Exception e) {
Logger.error(e); Logger.error(e);
@ -1396,6 +1397,11 @@ public class Mob extends AbstractIntelligenceAgent {
loadInventory(); loadInventory();
this.updateLocation(); this.updateLocation();
if(Mob.discDroppers.contains(this)){
this.setLevel((short)65);
this.setResists(new Resists("Dropper"));
}
} }
public void despawn() { public void despawn() {
@ -1466,7 +1472,7 @@ public class Mob extends AbstractIntelligenceAgent {
Logger.error(e.getMessage()); Logger.error(e.getMessage());
} }
Resists.calculateResists(this); //Resists.calculateResists(this);
} }
public void calculateMaxHealthManaStamina() { public void calculateMaxHealthManaStamina() {
@ -2263,5 +2269,9 @@ public class Mob extends AbstractIntelligenceAgent {
} }
} }
} }
public static void AddDiscDropper(Mob mob){
discDroppers.add(mob);
mob.setLevel((short)65);
mob.setResists(new Resists("Dropper"));
}
} }

4
src/engine/objects/MobEquipment.java

@ -34,7 +34,8 @@ public class MobEquipment extends AbstractGameObject {
private AbstractPowerAction suffix; private AbstractPowerAction suffix;
private int pValue; private int pValue;
private int sValue; private int sValue;
private int magicValue; int magicValue;
public boolean fromNoob = false;
private float dropChance = 0; private float dropChance = 0;
@ -106,7 +107,6 @@ public class MobEquipment extends AbstractGameObject {
public static void serializeForVendor(MobEquipment mobEquipment, ByteBufferWriter writer, float percent) throws SerializationException { public static void serializeForVendor(MobEquipment mobEquipment, ByteBufferWriter writer, float percent) throws SerializationException {
_serializeForClientMsg(mobEquipment, writer, false); _serializeForClientMsg(mobEquipment, writer, false);
int baseValue = mobEquipment.itemBase.getBaseValue() + mobEquipment.itemBase.getMagicValue();
writer.putInt(mobEquipment.magicValue); writer.putInt(mobEquipment.magicValue);
writer.putInt(mobEquipment.magicValue); writer.putInt(mobEquipment.magicValue);
} }

2
src/engine/objects/MobLoot.java

@ -77,7 +77,7 @@ public final class MobLoot extends Item {
this.setNumOfItems(quantity); this.setNumOfItems(quantity);
this.noSteal = noSteal; this.noSteal = noSteal;
this.setIsID(this.getItemBase().isAutoID()); this.setIsID(true);
// Class is 'final'; passing 'this' should be okay at the end of the constructor // Class is 'final'; passing 'this' should be okay at the end of the constructor

52
src/engine/objects/PlayerCharacter.java

@ -175,6 +175,10 @@ public class PlayerCharacter extends AbstractCharacter {
private boolean dirtyLoad = true; private boolean dirtyLoad = true;
private final ReadWriteLock dirtyLock = new ReentrantReadWriteLock(true); private final ReadWriteLock dirtyLock = new ReentrantReadWriteLock(true);
public float ZergMultiplier = 1.0f;
public boolean isBoxed = false;
/** /**
* No Id Constructor * No Id Constructor
*/ */
@ -4811,6 +4815,17 @@ public class PlayerCharacter extends AbstractCharacter {
updateBlessingMessage(); updateBlessingMessage();
this.safeZone = this.isInSafeZone(); this.safeZone = this.isInSafeZone();
if(!this.timestamps.containsKey("nextBoxCheck"))
this.timestamps.put("nextBoxCheck", System.currentTimeMillis() + 10000);
if(!this.isBoxed && this.timestamps.get("nextBoxCheck") < System.currentTimeMillis()) {
this.isBoxed = checkIfBoxed(this);
this.timestamps.put("nextBoxCheck", System.currentTimeMillis() + 10000);
}
if(this.isBoxed && !this.containsEffect(1672601862)) {
PowersManager.applyPower(this, this, Vector3fImmutable.ZERO, 1672601862, 40, false);
}
} catch (Exception e) { } catch (Exception e) {
Logger.error(e); Logger.error(e);
@ -4819,7 +4834,44 @@ public class PlayerCharacter extends AbstractCharacter {
} }
} }
} }
public static void unboxPlayer(PlayerCharacter player){
String machineID = player.getClientConnection().machineID;
ArrayList<PlayerCharacter> sameMachine = new ArrayList<>();
for(PlayerCharacter pc : SessionManager.getAllActivePlayerCharacters()){
if(!pc.equals(player) && pc. isActive && pc.isEnteredWorld() && pc.getClientConnection().machineID.equals(machineID)){
sameMachine.add(pc);
}
}
for(PlayerCharacter pc : sameMachine)
pc.isBoxed = true;
player.isBoxed = false;
if(player.containsEffect(1672601862)) {
player.removeEffectBySource(EffectSourceType.DeathShroud,41,false);
}
}
public static boolean checkIfBoxed(PlayerCharacter player){
try {
String machineID = player.getClientConnection().machineID;
ArrayList<PlayerCharacter> sameMachine = new ArrayList<>();
for (PlayerCharacter pc : SessionManager.getAllActivePlayerCharacters()) {
if (!pc.equals(player) && pc.isActive && pc.isEnteredWorld() && pc.getClientConnection().machineID.equals(machineID)) {
sameMachine.add(pc);
}
}
boolean boxed = false;
for (PlayerCharacter pc : sameMachine)
if (!pc.isBoxed)
boxed = true;
return boxed;
}catch(Exception e){
return false;
}
}
@Override @Override
public void updateFlight() { public void updateFlight() {

21
src/engine/objects/Resists.java

@ -46,6 +46,9 @@ public class Resists {
case "Mine": case "Mine":
setMineResists(); setMineResists();
break; break;
case "Dropper":
setDropperResists();
break;
default: default:
setGenericResists(); setGenericResists();
break; break;
@ -231,6 +234,24 @@ public class Resists {
this.resists.put(DamageType.Siege, 0f); this.resists.put(DamageType.Siege, 0f);
} }
public final void setDropperResists() {
this.immuneToAll = false;
this.resists.put(DamageType.Slash, 50f);
this.resists.put(DamageType.Crush, 50f);
this.resists.put(DamageType.Pierce, 50f);
this.resists.put(DamageType.Magic, 50f);
this.resists.put(DamageType.Bleed, 50f);
this.resists.put(DamageType.Poison, 50f);
this.resists.put(DamageType.Mental, 50f);
this.resists.put(DamageType.Holy, 50f);
this.resists.put(DamageType.Unholy, 50f);
this.resists.put(DamageType.Lightning, 50f);
this.resists.put(DamageType.Fire, 50f);
this.resists.put(DamageType.Cold, 50f);
this.resists.put(DamageType.Healing, 0f);
this.immuneTo.put(DamageType.Siege, true);
}
/** /**
* Create generic resists * Create generic resists
*/ */

27
src/engine/objects/Shrine.java

@ -43,7 +43,7 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
public static boolean canTakeFavor(PlayerCharacter grantee, Shrine shrine) { public static boolean canTakeFavor(PlayerCharacter grantee, Shrine shrine) {
if (shrine.shrineType.isRace()) if (shrine.shrineType.isRace()) {
switch (grantee.getRaceID()) { switch (grantee.getRaceID()) {
case 2000: case 2000:
case 2001: case 2001:
@ -96,6 +96,7 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
case 2025: case 2025:
case 2026: case 2026:
case 1999:
if (shrine.shrineType == ShrineType.Nephilim) if (shrine.shrineType == ShrineType.Nephilim)
return true; return true;
break; break;
@ -106,7 +107,7 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
break; break;
} }
else }else {
switch (grantee.getPromotionClassID()) { switch (grantee.getPromotionClassID()) {
case 2504: case 2504:
if (shrine.shrineType == ShrineType.Assassin) if (shrine.shrineType == ShrineType.Assassin)
@ -197,7 +198,7 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
return true; return true;
break; break;
} }
}
return false; return false;
} }
@ -226,26 +227,6 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
} }
public void decay() {
if (this.getFavors() == 0)
return;
int decayAmount = (int) (this.getFavors() - (this.getFavors() * .10f));
if (decayAmount < 0)
decayAmount = 0;
if (!DbManager.ShrineQueries.updateFavors(this, decayAmount, this.getFavors())) {
Logger.error("Shrine Decay", "Error writing to DB. UUID: " + this.getObjectUUID());
return;
}
this.favors = decayAmount;
Logger.info(shrineType.name() + " uuid:" + this.getObjectUUID() + " Amount: " + this.getFavors() * .10f);
}
public synchronized boolean addFavor(PlayerCharacter boonOwner, Item boonItem) { public synchronized boolean addFavor(PlayerCharacter boonOwner, Item boonItem) {
if (boonOwner == null) if (boonOwner == null)

78
src/engine/objects/Warehouse.java

@ -281,6 +281,84 @@ public class Warehouse extends AbstractWorldObject {
} }
public static int getCostForResource(int id){
int newCost = 1;
switch(id){
case 1580000://stone
newCost = 3000;
break;
case 1580001://truesteel
newCost = 50000;
break;
case 1580002://iron
newCost = 50000;
break;
case 1580003://adamant
newCost = 100000;
break;
case 1580004://lumber
newCost = 3000;
break;
case 1580005://oak
newCost = 30000;
break;
case 1580006://bronzewood
newCost = 30000;
break;
case 1580007://mandrake
newCost = 100000;
break;
case 1580008://coal
newCost = 30000;
break;
case 1580009://agate
newCost = 50000;
break;
case 1580010://diamond
newCost = 50000;
break;
case 1580011://onyx
newCost = 100000;
break;
case 1580012://azoth
newCost = 50000;
break;
case 1580013://orichalk
newCost = 30000;
break;
case 1580014://antimony
newCost = 100000;
break;
case 1580015://sulfur
newCost = 100000;
break;
case 1580016://quicksilver
newCost = 100000;
break;
case 1580017://galvor
newCost = 300000;
break;
case 1580018://wormwood
newCost = 300000;
break;
case 1580019://obsidian
newCost = 200000;
break;
case 1580020://bloodstone
newCost = 200000;
break;
case 1705032:
newCost = 100000;
break;
}
return newCost;
}
public static int getSellStackSize(int id){
if(id == 1705032)
return 10;
return 3000000 / getCostForResource(id);
}
public ConcurrentHashMap<ItemBase, Integer> getResources() { public ConcurrentHashMap<ItemBase, Integer> getResources() {
return resources; return resources;
} }

5
src/engine/objects/Zone.java

@ -101,7 +101,6 @@ public class Zone extends AbstractGameObject {
if (hash == null) if (hash == null)
setHash(); setHash();
} }
public static void serializeForClientMsg(Zone zone, ByteBufferWriter writer) { public static void serializeForClientMsg(Zone zone, ByteBufferWriter writer) {
@ -113,8 +112,8 @@ public class Zone extends AbstractGameObject {
if (zone.playerCityID > 0) { if (zone.playerCityID > 0) {
writer.put((byte) 1); // Player City - True writer.put((byte) 1); // Player City - True
writer.putFloat(Enum.CityBoundsType.ZONE.extents); writer.putFloat(Enum.CityBoundsType.GRID.extents);
writer.putFloat(Enum.CityBoundsType.ZONE.extents); writer.putFloat(Enum.CityBoundsType.GRID.extents);
} else } else
writer.put((byte) 0); // Player City - False writer.put((byte) 0); // Player City - False

22
src/engine/server/world/WorldServer.java

@ -40,10 +40,7 @@ import engine.net.client.msg.chat.ChatSystemMsg;
import engine.objects.*; import engine.objects.*;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.util.ThreadUtils; import engine.util.ThreadUtils;
import engine.workthreads.DisconnectTrashTask; import engine.workthreads.*;
import engine.workthreads.HourlyJobThread;
import engine.workthreads.PurgeOprhans;
import engine.workthreads.WarehousePushThread;
import org.pmw.tinylog.Configurator; import org.pmw.tinylog.Configurator;
import org.pmw.tinylog.Level; import org.pmw.tinylog.Level;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@ -201,6 +198,7 @@ public class WorldServer {
LocalDateTime nextPopulationFileTime = LocalDateTime.now(); LocalDateTime nextPopulationFileTime = LocalDateTime.now();
LocalDateTime nextFlashTrashCheckTime = LocalDateTime.now(); LocalDateTime nextFlashTrashCheckTime = LocalDateTime.now();
LocalDateTime nextHourlyJobTime = LocalDateTime.now().withMinute(0).withSecond(0).plusHours(1); LocalDateTime nextHourlyJobTime = LocalDateTime.now().withMinute(0).withSecond(0).plusHours(1);
LocalDateTime nextHalfHourlyJobTime = LocalDateTime.now().withMinute(0).withSecond(0);
LocalDateTime nextWareHousePushTime = LocalDateTime.now(); LocalDateTime nextWareHousePushTime = LocalDateTime.now();
// Begin execution of main game loop // Begin execution of main game loop
@ -232,6 +230,13 @@ public class WorldServer {
nextHourlyJobTime = LocalDateTime.now().withMinute(0).withSecond(0).plusHours(1); nextHourlyJobTime = LocalDateTime.now().withMinute(0).withSecond(0).plusHours(1);
} }
if (LocalDateTime.now().isAfter(nextHalfHourlyJobTime)) {
Thread halfHourlyJobThread = new Thread(new HalfHourlyJobThread());
halfHourlyJobThread.setName("halfHourlyJob");
halfHourlyJobThread.start();
nextHalfHourlyJobTime = nextHalfHourlyJobTime.plusMinutes(30);
}
if (LocalDateTime.now().isAfter(nextWareHousePushTime)) { if (LocalDateTime.now().isAfter(nextWareHousePushTime)) {
Thread warehousePushThread = new Thread(new WarehousePushThread()); Thread warehousePushThread = new Thread(new WarehousePushThread());
warehousePushThread.setName("warehousePush"); warehousePushThread.setName("warehousePush");
@ -435,9 +440,6 @@ public class WorldServer {
Logger.info("Loading Max Skills for Trainers"); Logger.info("Loading Max Skills for Trainers");
DbManager.SkillsBaseQueries.LOAD_ALL_MAX_SKILLS_FOR_CONTRACT(); DbManager.SkillsBaseQueries.LOAD_ALL_MAX_SKILLS_FOR_CONTRACT();
//pick a startup Hotzone
ZoneManager.generateAndSetRandomHotzone();
Logger.info("Loading All Players from database to Server Cache"); Logger.info("Loading All Players from database to Server Cache");
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
@ -488,8 +490,8 @@ public class WorldServer {
MobRespawnThread.startRespawnThread(); MobRespawnThread.startRespawnThread();
// Run maintenance // Run maintenance
//moved this to hourly job thread to sustain no reboot system
MaintenanceManager.dailyMaintenance(); //MaintenanceManager.dailyMaintenance();
Logger.info("Starting Orphan Item Purge"); Logger.info("Starting Orphan Item Purge");
PurgeOprhans.startPurgeThread(); PurgeOprhans.startPurgeThread();
@ -497,7 +499,7 @@ public class WorldServer {
// Open/Close mines for the current window // Open/Close mines for the current window
Logger.info("Processing mine window."); Logger.info("Processing mine window.");
HourlyJobThread.processMineWindow(); HalfHourlyJobThread.processMineWindow();
// Calculate bootstrap time and rest boot time to current time. // Calculate bootstrap time and rest boot time to current time.

166
src/engine/workthreads/HalfHourlyJobThread.java

@ -0,0 +1,166 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.workthreads;
import engine.Enum;
import engine.InterestManagement.WorldGrid;
import engine.db.archive.DataWarehouse;
import engine.db.archive.MineRecord;
import engine.gameManager.*;
import engine.net.DispatchMessage;
import engine.net.MessageDispatcher;
import engine.net.client.msg.chat.ChatSystemMsg;
import engine.objects.*;
import engine.server.world.WorldServer;
import org.pmw.tinylog.Logger;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import static engine.server.MBServerStatics.MINE_LATE_WINDOW;
public class HalfHourlyJobThread implements Runnable {
public HalfHourlyJobThread() {
}
public static void processMineWindow() {
try {
ArrayList<Mine> mines = Mine.getMines();
for (Mine mine : mines) {
try {
//handle mines opening on server reboot weird time interval
if(LocalDateTime.now().isAfter(LocalDateTime.now().withHour(mine.openHour).withMinute(mine.openMinute))) {
if (LocalDateTime.now().isBefore(LocalDateTime.now().withHour(mine.openHour).withMinute(mine.openMinute).plusMinutes(30))) {
HalfHourlyJobThread.mineWindowOpen(mine);
continue;
}
}
// set to the current mine window.
if (mine.openHour == LocalDateTime.now().getHour() && mine.openMinute == LocalDateTime.now().getMinute() && !mine.wasClaimed) {
HalfHourlyJobThread.mineWindowOpen(mine);
continue;
}
// Close the mine if it reaches this far
LocalDateTime openTime = LocalDateTime.now().withHour(mine.openHour).withMinute(mine.openMinute);
if(LocalDateTime.now().plusMinutes(1).isAfter(openTime.plusMinutes(30)))
mineWindowClose(mine);
} catch (Exception e) {
Logger.error("mineID: " + mine.getObjectUUID(), e.toString());
}
}
} catch (Exception e) {
Logger.error(e.toString());
}
}
public static void mineWindowOpen(Mine mine) {
mine.setActive(true);
ChatManager.chatSystemChannel(mine.getZoneName() + "'s Mine is now Active!");
Logger.info(mine.getZoneName() + "'s Mine is now Active!");
}
public static boolean mineWindowClose(Mine mine) {
// No need to end the window of a mine which never opened.
if (mine.isActive == false)
return false;
Building mineBuilding = BuildingManager.getBuildingFromCache(mine.getBuildingID());
if (mineBuilding == null) {
Logger.debug("Null mine building for Mine " + mine.getObjectUUID() + " Building " + mine.getBuildingID());
return false;
}
// Mine building still stands; nothing to do.
// We can early exit here.
if (mineBuilding.getRank() > 0) {
mine.setActive(false);
mine.lastClaimer = null;
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mine.guildName + " has defended the mine in " + mine.getParentZone().getParent().getName() + ". The mine is no longer active.");
chatMsg.setMessageType(10);
chatMsg.setChannel(Enum.ChatChannelType.SYSTEM.getChannelID());
DispatchMessage.dispatchMsgToAll(chatMsg);
return true;
}
// This mine does not have a valid claimer
// we will therefore set it to errant
// and keep the window open.
if (!Mine.validateClaimer(mine.lastClaimer)) {
mine.lastClaimer = null;
mine.updateGuildOwner(null);
mine.setActive(true);
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mine.getParentZone().getParent().getName() + " Was not claimed, the battle rages on!");
chatMsg.setMessageType(10);
chatMsg.setChannel(Enum.ChatChannelType.SYSTEM.getChannelID());
DispatchMessage.dispatchMsgToAll(chatMsg);
return false;
}
//Update ownership to map
mine.guildName = mine.getOwningGuild().getName();
mine.guildTag = mine.getOwningGuild().getGuildTag();
Guild nation = mine.getOwningGuild().getNation();
mine.nationName = nation.getName();
mine.nationTag = nation.getGuildTag();
mineBuilding.rebuildMine();
WorldGrid.updateObject(mineBuilding);
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mine.lastClaimer.getName() + " has claimed the mine in " + mine.getParentZone().getParent().getName() + " for " + mine.getOwningGuild().getName() + ". The mine is no longer active.");
chatMsg.setMessageType(10);
chatMsg.setChannel(Enum.ChatChannelType.SYSTEM.getChannelID());
DispatchMessage.dispatchMsgToAll(chatMsg);
// Warehouse this claim event
MineRecord mineRecord = MineRecord.borrow(mine, mine.lastClaimer, Enum.RecordEventType.CAPTURE);
DataWarehouse.pushToWarehouse(mineRecord);
mineBuilding.setRank(mineBuilding.getRank());
mine.lastClaimer = null;
mine.setActive(false);
mine.wasClaimed = true;
for(Integer id : mine._playerMemory){
PlayerCharacter pc = PlayerCharacter.getFromCache(id);
if(pc != null)
pc.ZergMultiplier = 1.0f;
}
return true;
}
public void run() {
Logger.info("Half-Hourly job is now running.");
// Open or Close mines for the current mine window.
processMineWindow();
}
}

257
src/engine/workthreads/HourlyJobThread.java

@ -10,13 +10,8 @@
package engine.workthreads; package engine.workthreads;
import engine.Enum; import engine.Enum;
import engine.InterestManagement.WorldGrid;
import engine.db.archive.DataWarehouse;
import engine.db.archive.MineRecord;
import engine.gameManager.*; import engine.gameManager.*;
import engine.net.DispatchMessage;
import engine.net.MessageDispatcher; import engine.net.MessageDispatcher;
import engine.net.client.msg.chat.ChatSystemMsg;
import engine.objects.*; import engine.objects.*;
import engine.server.world.WorldServer; import engine.server.world.WorldServer;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@ -25,240 +20,18 @@ import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import static engine.server.MBServerStatics.MINE_LATE_WINDOW;
public class HourlyJobThread implements Runnable { public class HourlyJobThread implements Runnable {
public HourlyJobThread() { public HourlyJobThread() {
} }
public static void decayShrines() {
ArrayList<Shrine> shrineList = new ArrayList<>();
for (Shrine shrine : Shrine.shrinesByBuildingUUID.values()) {
try {
Building shrineBuilding = (Building) DbManager.getObject(Enum.GameObjectType.Building, shrine.getBuildingID());
if (shrineBuilding == null)
continue;
if (shrineBuilding.getOwner().equals(shrineBuilding.getCity().getOwner()) == false)
shrineBuilding.claim(shrineBuilding.getCity().getOwner());
} catch (Exception e) {
Logger.info("Shrine " + shrine.getBuildingID() + " Error " + e);
}
}
// Grab list of top two shrines of each type
for (Shrine shrine : Shrine.shrinesByBuildingUUID.values()) {
if (shrine.getRank() == 0 || shrine.getRank() == 1)
shrineList.add(shrine);
}
Logger.info("Decaying " + shrineList.size() + " shrines...");
// Top 2 shrines decay by 10% a day
for (Shrine shrine : shrineList) {
try {
shrine.decay();
} catch (Exception e) {
Logger.info("Shrine " + shrine.getBuildingID() + " Error " + e);
}
}
}
public static void processMineWindow() {
try {
ArrayList<Mine> mines = Mine.getMines();
for (Mine mine : mines) {
if (LocalDateTime.now().getHour() == 1400) {
mine.wasClaimed = false;
}
try {
// Open Errant Mines
if (mine.getOwningGuild().isEmptyGuild()) {
HourlyJobThread.mineWindowOpen(mine);
continue;
}
// Open Mines owned by nations having their WOO
// set to the current mine window.
if (mine.getOwningGuild().getNation().getMineTime() ==
LocalDateTime.now().getHour() && mine.wasClaimed == false) {
HourlyJobThread.mineWindowOpen(mine);
continue;
}
// Close the mine if it reaches this far
mineWindowClose(mine);
} catch (Exception e) {
Logger.error("mineID: " + mine.getObjectUUID(), e.toString());
}
}
} catch (Exception e) {
Logger.error(e.toString());
}
}
public static void mineWindowOpen(Mine mine) {
mine.setActive(true);
ChatManager.chatSystemChannel(mine.getZoneName() + "'s Mine is now Active!");
Logger.info(mine.getZoneName() + "'s Mine is now Active!");
}
public static boolean mineWindowClose(Mine mine) {
// No need to end the window of a mine which never opened.
if (mine.isActive == false)
return false;
Building mineBuilding = BuildingManager.getBuildingFromCache(mine.getBuildingID());
if (mineBuilding == null) {
Logger.debug("Null mine building for Mine " + mine.getObjectUUID() + " Building " + mine.getBuildingID());
return false;
}
// Mine building still stands; nothing to do.
// We can early exit here.
if (mineBuilding.getRank() > 0) {
mine.setActive(false);
mine.lastClaimer = null;
return true;
}
// This mine does not have a valid claimer
// we will therefore set it to errant
// and keep the window open.
if (!Mine.validateClaimer(mine.lastClaimer)) {
mine.lastClaimer = null;
mine.updateGuildOwner(null);
mine.setActive(true);
return false;
}
//Update ownership to map
mine.guildName = mine.getOwningGuild().getName();
mine.guildTag = mine.getOwningGuild().getGuildTag();
Guild nation = mine.getOwningGuild().getNation();
mine.nationName = nation.getName();
mine.nationTag = nation.getGuildTag();
mineBuilding.rebuildMine();
WorldGrid.updateObject(mineBuilding);
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mine.lastClaimer.getName() + " has claimed the mine in " + mine.getParentZone().getParent().getName() + " for " + mine.getOwningGuild().getName() + ". The mine is no longer active.");
chatMsg.setMessageType(10);
chatMsg.setChannel(Enum.ChatChannelType.SYSTEM.getChannelID());
DispatchMessage.dispatchMsgToAll(chatMsg);
// Warehouse this claim event
MineRecord mineRecord = MineRecord.borrow(mine, mine.lastClaimer, Enum.RecordEventType.CAPTURE);
DataWarehouse.pushToWarehouse(mineRecord);
mineBuilding.setRank(mineBuilding.getRank());
mine.lastClaimer = null;
mine.setActive(false);
mine.wasClaimed = true;
return true;
}
public void run() { public void run() {
// *** REFACTOR: TRY TRY TRY TRY {{{{{{{{{{{ OMG // *** REFACTOR: TRY TRY TRY TRY {{{{{{{{{{{ OMG
Logger.info("Hourly job is now running."); Logger.info("Hourly job is now running.");
try {
// Use the same hotZone this hour up and until
// the HotZone_Duration from the ConfigManager
if (ZoneManager.hotZone == null)
ZoneManager.generateAndSetRandomHotzone();
else
ZoneManager.hotZoneCycle = ZoneManager.hotZoneCycle + 1;
if (ZoneManager.hotZoneCycle > Integer.parseInt(ConfigManager.MB_HOTZONE_DURATION.getValue()))
ZoneManager.generateAndSetRandomHotzone();
if (ZoneManager.hotZone == null) {
Logger.error("Null HotZone returned from ZoneManager");
} else {
Logger.info("HotZone switched to: " + ZoneManager.hotZone.getName());
}
} catch (Exception e) {
Logger.error(e.toString());
}
// Open or Close mines for the current mine window.
processMineWindow();
// Deposit mine resources to Guilds
for (Mine mine : Mine.getMines()) {
try {
mine.depositMineResources();
} catch (Exception e) {
Logger.info(e.getMessage() + " for Mine " + mine.getObjectUUID());
}
}
// Reset time-gated access to WOO slider.
// *** Do this after the mines open/close!
if (LocalDateTime.now().getHour() == MINE_LATE_WINDOW) {
Guild guild;
for (AbstractGameObject dbObject : DbManager.getList(Enum.GameObjectType.Guild)) {
guild = (Guild) dbObject;
if (guild != null)
guild.wooWasModified = false;
}
}
// Mines can only be claimed once per cycle.
// This will reset at 1am after the last mine
// window closes.
if (LocalDateTime.now().getHour() == MINE_LATE_WINDOW + 1) {
for (Mine mine : Mine.getMines()) {
if (mine.wasClaimed == true)
mine.wasClaimed = false;
}
}
// Decay Shrines at midnight every day
if (LocalDateTime.now().getHour() == MINE_LATE_WINDOW)
decayShrines();
// Update city population values // Update city population values
ConcurrentHashMap<Integer, AbstractGameObject> map = DbManager.getMap(Enum.GameObjectType.City); ConcurrentHashMap<Integer, AbstractGameObject> map = DbManager.getMap(Enum.GameObjectType.City);
@ -280,6 +53,36 @@ public class HourlyJobThread implements Runnable {
Logger.error("missing city map"); Logger.error("missing city map");
} }
//run maintenance every day at 2 am
if(LocalDateTime.now().getHour() == 2) {
MaintenanceManager.dailyMaintenance();
//produce mine resources once a day
for (Mine mine : Mine.getMines()) {
try {
mine.depositMineResources();
} catch (Exception e) {
Logger.info(e.getMessage() + " for Mine " + mine.getObjectUUID());
}
mine.wasClaimed = false;
}
}
switch(LocalDateTime.now().getHour()){
case 3:
case 6:
case 9:
case 12:
case 15:
case 18:
case 21:
case 0:
for(Mob mob : Mob.discDroppers)
if(!mob.isAlive())
Zone.respawnQue.add(mob);
break;
}
// Log metrics to console // Log metrics to console
Logger.info(WorldServer.getUptimeString()); Logger.info(WorldServer.getUptimeString());
Logger.info(SimulationManager.getPopulationString()); Logger.info(SimulationManager.getPopulationString());

Loading…
Cancel
Save