Compare commits

..
Author SHA1 Message Date
SlaveOfMagicbot 86062cf712 fix: null-safe upgradeDateTime conversion in BuildingManager.setUpgradeDateTime
Placing a banestone (and other callers) pass null to clear a fresh
building's upgrade timer, but the inline .atZone(...).toInstant() NPE'd
on null. Convert only when non-null; the DB layer already handles null.
2026-10-12 16:47:26 -05:00
SlaveOfMagicbot 85cd4e0c14 fix: use LocalDateTime for mine late-window calc in ArcMineWindowAvailableTimeMsg
Instant has no hour-of-day field, so .with(HOUR_OF_DAY, ...) threw
UnsupportedTemporalTypeException. Switch lateTime to LocalDateTime so the
late-window (midnight) time can be set and the seconds-remaining computed.
2026-10-12 12:44:27 -05:00
SlaveOfMagicbot 8a136d84f4 refactor: migrate JodaTime to java.time (rebuild on subdate2 ab96cfc)
Complete the JodaTime -> java.time migration across 30 files on the
correct subdate2 base. No org.joda references remain.
2026-10-09 20:12:23 -05:00
153 changed files with 2860 additions and 7491 deletions

No files matched your search

@@ -468,12 +468,7 @@ public enum InterestManager implements Runnable {
continue; continue;
awonpc.playerAgroMap.put(player.getObjectUUID(), 0f); awonpc.playerAgroMap.put(player.getObjectUUID(), 0f);
((Mob) awonpc).setCombatTarget(null);
// siege engines keep firing at their target when a new player loads them
if (!awonpc.isSiege())
((Mob) awonpc).setCombatTarget(null);
lcm = new LoadCharacterMsg(awonpc, PlayerCharacter.hideNonAscii()); lcm = new LoadCharacterMsg(awonpc, PlayerCharacter.hideNonAscii());
} else if ((awo.getObjectTypeMask() & MBServerStatics.MASK_NPC) != 0) { } else if ((awo.getObjectTypeMask() & MBServerStatics.MASK_NPC) != 0) {
+10 -11
View File
@@ -14,7 +14,6 @@ import engine.mbEnums;
import engine.objects.Bane; import engine.objects.Bane;
import engine.objects.City; import engine.objects.City;
import engine.workthreads.WarehousePushThread; import engine.workthreads.WarehousePushThread;
import org.joda.time.DateTime;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.*; import java.sql.*;
@@ -34,8 +33,8 @@ public class BaneRecord extends DataRecord {
private String baneDropperHash; private String baneDropperHash;
private String baneGuildHash; private String baneGuildHash;
private String baneNationHash; private String baneNationHash;
private DateTime baneLiveTime; private LocalDateTime baneLiveTime;
private DateTime baneDropTime; private LocalDateTime baneDropTime;
private BaneRecord(Bane bane) { private BaneRecord(Bane bane) {
this.recordType = mbEnums.DataRecordType.BANE; this.recordType = mbEnums.DataRecordType.BANE;
@@ -129,9 +128,9 @@ public class BaneRecord extends DataRecord {
return outStatement; return outStatement;
} }
public static DateTime getLastBaneDateTime(City city) { public static LocalDateTime getLastBaneDateTime(City city) {
DateTime outDateTime = null; LocalDateTime outDateTime = null;
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement statement = buildDateTimeQueryStatement(connection, city); PreparedStatement statement = buildDateTimeQueryStatement(connection, city);
@@ -139,7 +138,7 @@ public class BaneRecord extends DataRecord {
while (rs.next()) { while (rs.next()) {
outDateTime = new DateTime(rs.getTimestamp("endDatetime")); outDateTime = rs.getTimestamp("endDatetime").toLocalDateTime();
} }
@@ -160,7 +159,7 @@ public class BaneRecord extends DataRecord {
} }
public static void updateLiveDate(Bane bane, DateTime dateTime) { public static void updateLiveDate(Bane bane, LocalDateTime dateTime) {
if (bane == null) if (bane == null)
return; return;
@@ -175,13 +174,13 @@ public class BaneRecord extends DataRecord {
} }
} }
private static PreparedStatement buildUpdateLiveDateStatement(Connection connection, Bane bane, DateTime dateTime) throws SQLException { private static PreparedStatement buildUpdateLiveDateStatement(Connection connection, Bane bane, LocalDateTime dateTime) throws SQLException {
PreparedStatement outStatement = null; PreparedStatement outStatement = null;
String queryString = "UPDATE `warehouse_banehistory` SET `liveDatetime` = ?, `dirty` = 1 WHERE `city_id` = ? AND `resolution` = 'PENDING'"; String queryString = "UPDATE `warehouse_banehistory` SET `liveDatetime` = ?, `dirty` = 1 WHERE `city_id` = ? AND `resolution` = 'PENDING'";
outStatement = connection.prepareStatement(queryString); outStatement = connection.prepareStatement(queryString);
outStatement.setTimestamp(1, new java.sql.Timestamp(dateTime.getMillis())); outStatement.setTimestamp(1, Timestamp.valueOf(dateTime));
outStatement.setString(2, bane.getCity().getHash()); outStatement.setString(2, bane.getCity().getHash());
return outStatement; return outStatement;
@@ -366,12 +365,12 @@ public class BaneRecord extends DataRecord {
if (this.baneDropTime == null) if (this.baneDropTime == null)
outStatement.setNull(8, java.sql.Types.DATE); outStatement.setNull(8, java.sql.Types.DATE);
else else
outStatement.setTimestamp(8, new java.sql.Timestamp(this.baneDropTime.getMillis())); outStatement.setTimestamp(8, Timestamp.valueOf(this.baneDropTime));
if (this.baneLiveTime == null) if (this.baneLiveTime == null)
outStatement.setNull(9, java.sql.Types.DATE); outStatement.setNull(9, java.sql.Types.DATE);
else else
outStatement.setTimestamp(9, new java.sql.Timestamp(this.baneLiveTime.getMillis())); outStatement.setTimestamp(9, Timestamp.valueOf(this.baneLiveTime));
outStatement.setString(10, this.eventType.name()); outStatement.setString(10, this.eventType.name());
+3 -3
View File
@@ -14,7 +14,7 @@ import engine.objects.Bane;
import engine.objects.Building; import engine.objects.Building;
import engine.objects.City; import engine.objects.City;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import org.joda.time.DateTime; import java.time.LocalDateTime;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@@ -71,12 +71,12 @@ public class dbBaneHandler extends dbHandlerBase {
} }
public boolean SET_BANE_TIME(DateTime toSet, int cityUUID) { public boolean SET_BANE_TIME(LocalDateTime toSet, int cityUUID) {
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE `dyn_banes` SET `liveDate`=? WHERE `cityUUID`=?")) { PreparedStatement preparedStatement = connection.prepareStatement("UPDATE `dyn_banes` SET `liveDate`=? WHERE `cityUUID`=?")) {
preparedStatement.setTimestamp(1, new java.sql.Timestamp(toSet.getMillis())); preparedStatement.setTimestamp(1, java.sql.Timestamp.valueOf(toSet));
preparedStatement.setLong(2, cityUUID); preparedStatement.setLong(2, cityUUID);
preparedStatement.execute(); preparedStatement.execute();
@@ -17,7 +17,9 @@ import engine.mbEnums.DbObjectType;
import engine.mbEnums.ProtectionState; import engine.mbEnums.ProtectionState;
import engine.mbEnums.TaxType; import engine.mbEnums.TaxType;
import engine.objects.*; import engine.objects.*;
import org.joda.time.DateTime; import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@@ -40,7 +42,7 @@ public class dbBuildingHandler extends dbHandlerBase {
public Building CREATE_BUILDING(int parentZoneID, int OwnerUUID, String name, int meshUUID, public Building CREATE_BUILDING(int parentZoneID, int OwnerUUID, String name, int meshUUID,
Vector3fImmutable location, float meshScale, int currentHP, Vector3fImmutable location, float meshScale, int currentHP,
ProtectionState protectionState, int currentGold, int rank, ProtectionState protectionState, int currentGold, int rank,
DateTime upgradeDate, int blueprintUUID, float w, float rotY) { Instant upgradeDate, int blueprintUUID, float w, float rotY) {
Building building = null; Building building = null;
@@ -61,7 +63,7 @@ public class dbBuildingHandler extends dbHandlerBase {
preparedStatement.setInt(12, rank); preparedStatement.setInt(12, rank);
if (upgradeDate != null) if (upgradeDate != null)
preparedStatement.setTimestamp(13, new java.sql.Timestamp(upgradeDate.getMillis())); preparedStatement.setTimestamp(13, new java.sql.Timestamp(upgradeDate.toEpochMilli()));
else else
preparedStatement.setNull(13, java.sql.Types.DATE); preparedStatement.setNull(13, java.sql.Types.DATE);
@@ -749,7 +751,7 @@ public class dbBuildingHandler extends dbHandlerBase {
return false; return false;
} }
public boolean updateBuildingUpgradeTime(LocalDateTime upgradeDateTime, Building toUpgrade, int costToUpgrade) { public boolean updateBuildingUpgradeTime(Instant upgradeDateTime, Building toUpgrade, int costToUpgrade) {
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE obj_building SET upgradeDate=?, currentGold=? " PreparedStatement preparedStatement = connection.prepareStatement("UPDATE obj_building SET upgradeDate=?, currentGold=? "
@@ -758,8 +760,7 @@ public class dbBuildingHandler extends dbHandlerBase {
if (upgradeDateTime == null) if (upgradeDateTime == null)
preparedStatement.setNull(1, java.sql.Types.DATE); preparedStatement.setNull(1, java.sql.Types.DATE);
else else
preparedStatement.setTimestamp(1, new java.sql.Timestamp(upgradeDateTime.atZone(ZoneId.systemDefault()) preparedStatement.setTimestamp(1, new java.sql.Timestamp(upgradeDateTime.toEpochMilli()));
.toInstant().toEpochMilli()));
preparedStatement.setInt(2, toUpgrade.getStrongboxValue() - costToUpgrade); preparedStatement.setInt(2, toUpgrade.getStrongboxValue() - costToUpgrade);
preparedStatement.setInt(3, toUpgrade.getObjectUUID()); preparedStatement.setInt(3, toUpgrade.getObjectUUID());
@@ -838,7 +839,7 @@ public class dbBuildingHandler extends dbHandlerBase {
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE obj_building SET taxDate=? " PreparedStatement preparedStatement = connection.prepareStatement("UPDATE obj_building SET taxDate=? "
+ "WHERE UID = ?")) { + "WHERE UID = ?")) {
preparedStatement.setTimestamp(1, new java.sql.Timestamp(DateTime.now().plusDays(7).getMillis())); preparedStatement.setTimestamp(1, new java.sql.Timestamp(Instant.now().plus(7, java.time.temporal.ChronoUnit.DAYS).toEpochMilli()));
preparedStatement.setInt(2, building.getObjectUUID()); preparedStatement.setInt(2, building.getObjectUUID());
return (preparedStatement.executeUpdate() > 0); return (preparedStatement.executeUpdate() > 0);
+3 -3
View File
@@ -14,7 +14,7 @@ import engine.mbEnums;
import engine.mbEnums.GuildHistoryType; import engine.mbEnums.GuildHistoryType;
import engine.objects.*; import engine.objects.*;
import engine.server.world.WorldServer; import engine.server.world.WorldServer;
import org.joda.time.DateTime; import java.time.Instant;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.*; import java.sql.*;
@@ -125,7 +125,7 @@ public class dbGuildHandler extends dbHandlerBase {
return false; return false;
} }
public boolean ADD_TO_GUILDHISTORY(int target, PlayerCharacter playerCharacter, DateTime historyDate, GuildHistoryType historyType) { public boolean ADD_TO_GUILDHISTORY(int target, PlayerCharacter playerCharacter, Instant historyDate, GuildHistoryType historyType) {
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO `dyn_character_guildhistory` (`GuildID`, `CharacterID`, `historyDate`, `historyType`) VALUES (?,?,?,?)")) { PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO `dyn_character_guildhistory` (`GuildID`, `CharacterID`, `historyDate`, `historyType`) VALUES (?,?,?,?)")) {
@@ -136,7 +136,7 @@ public class dbGuildHandler extends dbHandlerBase {
if (historyDate == null) if (historyDate == null)
preparedStatement.setNull(3, java.sql.Types.DATE); preparedStatement.setNull(3, java.sql.Types.DATE);
else else
preparedStatement.setTimestamp(3, new Timestamp(historyDate.getMillis())); preparedStatement.setTimestamp(3, java.sql.Timestamp.from(historyDate));
preparedStatement.setString(4, historyType.name()); preparedStatement.setString(4, historyType.name());
+35 -9
View File
@@ -16,6 +16,8 @@ import engine.mbEnums.ItemType;
import engine.objects.AbstractCharacter; import engine.objects.AbstractCharacter;
import engine.objects.CharacterItemManager; import engine.objects.CharacterItemManager;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.ItemTemplate;
import org.json.JSONObject;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@@ -175,23 +177,47 @@ public class dbItemHandler extends dbHandlerBase {
return itemList; return itemList;
} }
public HashMap<Integer, Integer> LOAD_TEMPLATE_MODTABLES() { public void LOAD_ITEM_TEMPLATES() {
HashMap<Integer, Integer> modTables = new HashMap<>(); HashMap<ItemType, Integer> templateTCountMap = new HashMap<>();
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_item_templates`;");
ResultSet rs = preparedStatement.executeQuery()) {
while (rs.next()) {
int templateID = rs.getInt("id");
JSONObject jsonObject = new JSONObject(rs.getString("template"));
ItemTemplate itemTemplate = new ItemTemplate(jsonObject);
itemTemplate.template_id = templateID;
ItemTemplate.templates.put(templateID, itemTemplate);
templateTCountMap.merge(itemTemplate.item_type, 1, Integer::sum);
}
Logger.info(templateTCountMap.toString());
} catch (Exception e) {
Logger.error(e);
}
}
public void LOAD_TEMPLATE_MODTABLES() {
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_vendor_items`;"); PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_vendor_items`;");
ResultSet rs = preparedStatement.executeQuery()) { ResultSet rs = preparedStatement.executeQuery()) {
while (rs.next()) while (rs.next()) {
modTables.put(rs.getInt("templateID"), rs.getInt("modTable")); int templateID = rs.getInt("templateID");
int modTable = rs.getInt("modTable");
ItemTemplate template = ItemTemplate.templates.get(templateID);
template.modTable = modTable;
}
} catch (Exception e) { } catch (Exception e) {
Logger.error(e); Logger.error(e);
} }
Logger.info("read: " + modTables.size());
return modTables;
} }
public Item GET_ITEM(final int itemUUID) { public Item GET_ITEM(final int itemUUID) {
@@ -299,7 +325,7 @@ public class dbItemHandler extends dbHandlerBase {
for (Item item : inventory) { for (Item item : inventory) {
if (item.template.getItemType().equals(ItemType.GOLD)) if (item.template.item_type.equals(ItemType.GOLD))
continue; continue;
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
@@ -448,7 +474,7 @@ public class dbItemHandler extends dbHandlerBase {
*/ */
public boolean UPDATE_GOLD(final Item item, int newValue, int oldValue) { public boolean UPDATE_GOLD(final Item item, int newValue, int oldValue) {
if (!item.template.getItemType().equals(ItemType.GOLD)) if (!item.template.item_type.equals(ItemType.GOLD))
return false; return false;
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
@@ -528,7 +554,7 @@ public class dbItemHandler extends dbHandlerBase {
// Write 0 if we will not modify the value from template // Write 0 if we will not modify the value from template
if (value == item.template.getItemValue()) if (value == item.template.item_value)
value = 0; value = 0;
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
+4 -3
View File
@@ -12,7 +12,8 @@ package engine.db.handlers;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.mbEnums; import engine.mbEnums;
import engine.objects.Mob; import engine.objects.Mob;
import org.joda.time.DateTime; import java.time.LocalDateTime;
import java.time.ZoneId;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@@ -82,7 +83,7 @@ public class dbMobHandler extends dbHandlerBase {
return mobileList; return mobileList;
} }
public boolean updateUpgradeTime(Mob mob, DateTime upgradeDateTime) { public boolean updateUpgradeTime(Mob mob, LocalDateTime upgradeDateTime) {
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE obj_mob SET upgradeDate=? " PreparedStatement preparedStatement = connection.prepareStatement("UPDATE obj_mob SET upgradeDate=? "
@@ -91,7 +92,7 @@ public class dbMobHandler extends dbHandlerBase {
if (upgradeDateTime == null) if (upgradeDateTime == null)
preparedStatement.setNull(1, java.sql.Types.DATE); preparedStatement.setNull(1, java.sql.Types.DATE);
else else
preparedStatement.setTimestamp(1, new java.sql.Timestamp(upgradeDateTime.getMillis())); preparedStatement.setTimestamp(1, new java.sql.Timestamp(upgradeDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()));
preparedStatement.setInt(2, mob.getObjectUUID()); preparedStatement.setInt(2, mob.getObjectUUID());
+5 -4
View File
@@ -15,7 +15,8 @@ import engine.mbEnums;
import engine.mbEnums.ProfitType; import engine.mbEnums.ProfitType;
import engine.objects.NPC; import engine.objects.NPC;
import engine.objects.NPCProfits; import engine.objects.NPCProfits;
import org.joda.time.DateTime; import java.time.LocalDateTime;
import java.time.ZoneId;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@@ -57,7 +58,7 @@ public class dbNPCHandler extends dbHandlerBase {
runeSets.put(runeSetID, runeList); runeSets.put(runeSetID, runeList);
} else { } else {
ArrayList<Integer> runeList = runeSets.get(runeSetID); ArrayList<Integer> runeList = runeSets.get(runeSetID);
runeList.add(runeBaseID); runeList.add(runeSetID);
runeSets.put(runeSetID, runeList); runeSets.put(runeSetID, runeList);
} }
} }
@@ -240,7 +241,7 @@ public class dbNPCHandler extends dbHandlerBase {
} }
} }
public boolean updateUpgradeTime(NPC npc, DateTime upgradeDateTime) { public boolean updateUpgradeTime(NPC npc, LocalDateTime upgradeDateTime) {
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE obj_npc SET upgradeDate=? " PreparedStatement preparedStatement = connection.prepareStatement("UPDATE obj_npc SET upgradeDate=? "
@@ -249,7 +250,7 @@ public class dbNPCHandler extends dbHandlerBase {
if (upgradeDateTime == null) if (upgradeDateTime == null)
preparedStatement.setNull(1, java.sql.Types.DATE); preparedStatement.setNull(1, java.sql.Types.DATE);
else else
preparedStatement.setTimestamp(1, new java.sql.Timestamp(upgradeDateTime.getMillis())); preparedStatement.setTimestamp(1, new java.sql.Timestamp(upgradeDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()));
preparedStatement.setInt(2, npc.getObjectUUID()); preparedStatement.setInt(2, npc.getObjectUUID());
@@ -50,15 +50,7 @@ public class dbPromotionClassHandler extends dbHandlerBase {
public PromotionClass GET_PROMOTION_CLASS(final int objectUUID) { public PromotionClass GET_PROMOTION_CLASS(final int objectUUID) {
PromotionClass promotionClass; PromotionClass promotionClass = null;
if (objectUUID == 0)
return null;
promotionClass = (PromotionClass) DbManager.getFromCache(mbEnums.GameObjectType.PromotionClass, objectUUID);
if (promotionClass != null)
return promotionClass;
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_rune_promotion` WHERE `ID` = ?")) { PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_rune_promotion` WHERE `ID` = ?")) {
+3 -3
View File
@@ -16,7 +16,7 @@ import engine.mbEnums.ProtectionState;
import engine.objects.AbstractGameObject; import engine.objects.AbstractGameObject;
import engine.objects.Building; import engine.objects.Building;
import engine.objects.Shrine; import engine.objects.Shrine;
import org.joda.time.DateTime; import java.time.Instant;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@@ -53,7 +53,7 @@ public class dbShrineHandler extends dbHandlerBase {
public ArrayList<AbstractGameObject> CREATE_SHRINE(int parentZoneID, int OwnerUUID, String name, int meshUUID, public ArrayList<AbstractGameObject> CREATE_SHRINE(int parentZoneID, int OwnerUUID, String name, int meshUUID,
Vector3fImmutable location, float meshScale, int currentHP, Vector3fImmutable location, float meshScale, int currentHP,
ProtectionState protectionState, int currentGold, int rank, ProtectionState protectionState, int currentGold, int rank,
DateTime upgradeDate, int blueprintUUID, float w, float rotY, String shrineType) { Instant upgradeDate, int blueprintUUID, float w, float rotY, String shrineType) {
ArrayList<AbstractGameObject> shrineList = new ArrayList<>(); ArrayList<AbstractGameObject> shrineList = new ArrayList<>();
@@ -74,7 +74,7 @@ public class dbShrineHandler extends dbHandlerBase {
preparedStatement.setInt(12, rank); preparedStatement.setInt(12, rank);
if (upgradeDate != null) if (upgradeDate != null)
preparedStatement.setTimestamp(13, new java.sql.Timestamp(upgradeDate.getMillis())); preparedStatement.setTimestamp(13, java.sql.Timestamp.from(upgradeDate));
else else
preparedStatement.setNull(13, java.sql.Types.DATE); preparedStatement.setNull(13, java.sql.Types.DATE);
+8 -22
View File
@@ -20,9 +20,8 @@ import engine.objects.City;
import engine.objects.Transaction; import engine.objects.Transaction;
import engine.objects.Warehouse; import engine.objects.Warehouse;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import java.time.Instant;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -41,7 +40,7 @@ public class dbWarehouseHandler extends dbHandlerBase {
} }
public boolean CREATE_TRANSACTION(int warehouseBuildingID, GameObjectType targetType, int targetUUID, TransactionType transactionType, mbEnums.ResourceType resource, int amount, DateTime date) { public boolean CREATE_TRANSACTION(int warehouseBuildingID, GameObjectType targetType, int targetUUID, TransactionType transactionType, mbEnums.ResourceType resource, int amount, Instant date) {
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO `dyn_warehouse_transactions` (`warehouseUID`, `targetType`,`targetUID`, `type`,`resource`,`amount`,`date` ) VALUES (?,?,?,?,?,?,?)")) { PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO `dyn_warehouse_transactions` (`warehouseUID`, `targetType`,`targetUID`, `type`,`resource`,`amount`,`date` ) VALUES (?,?,?,?,?,?,?)")) {
@@ -52,7 +51,7 @@ public class dbWarehouseHandler extends dbHandlerBase {
preparedStatement.setString(4, transactionType.name()); preparedStatement.setString(4, transactionType.name());
preparedStatement.setString(5, resource.name()); preparedStatement.setString(5, resource.name());
preparedStatement.setInt(6, amount); preparedStatement.setInt(6, amount);
preparedStatement.setTimestamp(7, new java.sql.Timestamp(date.getMillis())); preparedStatement.setTimestamp(7, new java.sql.Timestamp(date.toEpochMilli()));
return (preparedStatement.executeUpdate() > 0); return (preparedStatement.executeUpdate() > 0);
@@ -135,6 +134,7 @@ public class dbWarehouseHandler extends dbHandlerBase {
while (rs.next()) { while (rs.next()) {
int cityUID = rs.getInt("cityUUID"); int cityUID = rs.getInt("cityUUID");
JSONObject jsonObject = new JSONObject(rs.getString("warehouse"));
City city = City.getCity(cityUID); City city = City.getCity(cityUID);
if (city == null) { if (city == null) {
@@ -142,18 +142,12 @@ public class dbWarehouseHandler extends dbHandlerBase {
continue; continue;
} }
try { city.warehouse = new Warehouse(jsonObject);
city.warehouse = new Warehouse(new JSONObject(rs.getString("warehouse")));
} catch (JSONException e) {
Logger.error("Warehouse for city " + cityUID + " failed to load: " + e.getMessage());
continue;
}
city.warehouse.city = city; city.warehouse.city = city;
// Locate warehouse building // Locate warehouse building
for (Building building : city.parentZone.zoneBuildingSet) { for (Building building : city.parentZone.zoneBuildingSet) {
if (building.getBlueprint().getBuildingGroup().equals(mbEnums.BuildingGroup.WAREHOUSE) && building.getRank() != -1) { if (building.getBlueprint().getBuildingGroup().equals(mbEnums.BuildingGroup.WAREHOUSE)) {
city.warehouse.building = building; city.warehouse.building = building;
break; break;
} }
@@ -211,16 +205,8 @@ public class dbWarehouseHandler extends dbHandlerBase {
ResultSet rs = preparedStatement.executeQuery()) { ResultSet rs = preparedStatement.executeQuery()) {
while (rs.next()) { while (rs.next()) {
int workOrderID = rs.getInt("workorderID"); JSONObject jsonObject = new JSONObject(rs.getString("workorder"));
WorkOrder workOrder; WorkOrder workOrder = new WorkOrder(jsonObject);
try {
workOrder = new WorkOrder(new JSONObject(rs.getString("workorder")));
} catch (JSONException e) {
Logger.error("WorkOrder " + workOrderID + " failed to load: " + e.getMessage());
continue;
}
submitList.add(workOrder); submitList.add(workOrder);
} }
} catch (Exception e) { } catch (Exception e) {
+3 -3
View File
@@ -15,8 +15,8 @@ import engine.gameManager.DbManager;
import engine.mbEnums; import engine.mbEnums;
import engine.objects.AbstractGameObject; import engine.objects.AbstractGameObject;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.ItemTemplate;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.parsers.objects.CObjectTemplate;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
/** /**
@@ -38,7 +38,7 @@ public class CreateItemCmd extends AbstractDevCmd {
} }
int templateID = Integer.parseInt(words[0]); int templateID = Integer.parseInt(words[0]);
CObjectTemplate template = CObjectTemplate.lookup(templateID); ItemTemplate template = ItemTemplate.templates.get(templateID);
if (template == null) { if (template == null) {
ChatManager.chatSystemInfo(playerCharacter, "No such template found."); ChatManager.chatSystemInfo(playerCharacter, "No such template found.");
@@ -51,7 +51,7 @@ public class CreateItemCmd extends AbstractDevCmd {
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (!playerCharacter.charItemManager.hasRoomInventory(template.getItemWt())) { if (!playerCharacter.charItemManager.hasRoomInventory(template.item_wt)) {
ChatManager.chatSystemInfo(playerCharacter, "You are encumbered!."); ChatManager.chatSystemInfo(playerCharacter, "You are encumbered!.");
break; break;
} }
-106
View File
@@ -1,106 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd;
import engine.gameManager.ChatManager;
import engine.gameManager.DbManager;
import engine.mbEnums;
import engine.objects.AbstractGameObject;
import engine.objects.Building;
import engine.objects.City;
import engine.objects.PlayerCharacter;
import engine.objects.Warehouse;
import java.util.HashMap;
public class FillCmd extends AbstractDevCmd {
public FillCmd() {
super("fill");
}
@Override
protected void _doCmd(PlayerCharacter pc, String[] words,
AbstractGameObject target) {
Building building;
City city;
Warehouse warehouse;
int amount = Integer.MAX_VALUE;
HashMap<mbEnums.ResourceType, Integer> oldResources;
if (words.length > 1) {
this.sendUsage(pc);
return;
}
if (words.length == 1 && !words[0].isEmpty()) {
try {
amount = Integer.parseInt(words[0]);
} catch (NumberFormatException e) {
throwbackError(pc, "Amount must be a number, " + words[0] + " is invalid");
return;
}
if (amount < 0) {
throwbackError(pc, "Amount must be 0 or more");
return;
}
}
if (target == null || target.getObjectType() != mbEnums.GameObjectType.Building) {
throwbackError(pc, "Select a warehouse");
return;
}
building = (Building) target;
if (building.getBlueprint() == null || building.getBlueprint().getBuildingGroup() != mbEnums.BuildingGroup.WAREHOUSE) {
throwbackError(pc, "Selected building is not a warehouse");
return;
}
city = building.getCity();
if (city == null || city.warehouse == null || city.warehouse.building == null
|| city.warehouse.building.getObjectUUID() != building.getObjectUUID()) {
throwbackError(pc, "Selected warehouse is not the active warehouse of a city");
return;
}
warehouse = city.warehouse;
oldResources = new HashMap<>(warehouse.resources);
for (mbEnums.ResourceType resourceType : mbEnums.ResourceType.values())
warehouse.resources.put(resourceType, Math.min(amount, resourceType.deposit_limit));
if (!DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse)) {
warehouse.resources.putAll(oldResources);
throwbackError(pc, "Failed to update the warehouse in the database");
return;
}
ChatManager.chatSayInfo(pc, "Filled the " + city.getCityName() + " warehouse"
+ (amount == Integer.MAX_VALUE ? " to each deposit limit" : " with " + amount + " of each resource (capped at the deposit limit)"));
}
@Override
protected String _getHelpString() {
return "Sets every resource in the selected warehouse";
}
@Override
protected String _getUsageString() {
return "' ./fill [amount]' with a warehouse selected (no amount fills each resource to its deposit limit)";
}
}
+5 -6
View File
@@ -18,7 +18,6 @@ import engine.mbEnums.BuildingGroup;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.mbEnums.TargetColor; import engine.mbEnums.TargetColor;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.util.StringUtils; import engine.util.StringUtils;
import java.text.DecimalFormat; import java.text.DecimalFormat;
@@ -508,17 +507,17 @@ public class InfoCmd extends AbstractDevCmd {
case Item: //intentional passthrough case Item: //intentional passthrough
case MobLoot: case MobLoot:
Item item = (Item) target; Item item = (Item) target;
CObjectTemplate template = CObjectTemplate.lookup(item.templateID); ItemTemplate template = ItemTemplate.templates.get(item.templateID);
output += StringUtils.addWS("Template: " + template.getTemplateId(), 20); output += StringUtils.addWS("Template: " + template.template_id, 20);
output += "Weight: " + template.getItemWt(); output += "Weight: " + template.item_wt;
output += newline; output += newline;
DecimalFormat df = new DecimalFormat("###,###,###,###,##0"); DecimalFormat df = new DecimalFormat("###,###,###,###,##0");
output += StringUtils.addWS("Qty: " output += StringUtils.addWS("Qty: "
+ df.format(item.getNumOfItems()), 20); + df.format(item.getNumOfItems()), 20);
output += "Charges: " + (byte) item.chargesRemaining output += "Charges: " + (byte) item.chargesRemaining
+ '/' + item.template.getItemInitialCharges(); + '/' + item.template.item_initial_charges;
output += newline; output += newline;
output += "Name: " + template.getItemBaseName(); output += "Name: " + template.item_base_name;
output += newline; output += newline;
output += item.getContainerInfo(); output += item.getContainerInfo();
+9 -16
View File
@@ -11,11 +11,9 @@ package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd; import engine.devcmd.AbstractDevCmd;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.mbEnums.ItemContainerType;
import engine.mbEnums.ItemType; import engine.mbEnums.ItemType;
import engine.mbEnums.OwnerType; import engine.mbEnums.OwnerType;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
/** /**
@@ -61,17 +59,18 @@ public class MakeItemCmd extends AbstractDevCmd {
} }
int templateID; int templateID;
CObjectTemplate template; ItemTemplate template;
try { try {
templateID = Integer.parseInt(words[0]); templateID = Integer.parseInt(words[0]);
template = CObjectTemplate.lookup(templateID); template = ItemTemplate.templates.get(words[0].toLowerCase());
if (template == null) { if (template == null) {
throwbackError(pc, "No item template with id " + words[0]); throwbackError(pc, "Supplied type " + words[0]
+ " failed to parse to an Integer");
return; return;
} }
if (template.getItemType() == ItemType.GOLD) { if (template.item_type == ItemType.GOLD) {
this.throwbackInfo(pc, "use /addgold to add gold."); this.throwbackInfo(pc, "use /addgold to add gold.");
return; return;
} }
@@ -133,7 +132,7 @@ public class MakeItemCmd extends AbstractDevCmd {
return; return;
} }
} }
template = CObjectTemplate.lookup(templateID); template = ItemTemplate.templates.get(templateID);
if (template == null) { if (template == null) {
throwbackError(pc, "Unable to find template " + templateID); throwbackError(pc, "Unable to find template " + templateID);
@@ -141,8 +140,8 @@ public class MakeItemCmd extends AbstractDevCmd {
} }
if ((numItems > 1) if ((numItems > 1)
&& (template.getItemType().equals(ItemType.RESOURCE) == false) && (template.item_type.equals(ItemType.RESOURCE) == false)
&& (template.getItemType().equals(ItemType.OFFERING)) == false) && (template.item_type.equals(ItemType.OFFERING)) == false)
numItems = 1; numItems = 1;
CharacterItemManager cim = pc.charItemManager; CharacterItemManager cim = pc.charItemManager;
@@ -156,7 +155,7 @@ public class MakeItemCmd extends AbstractDevCmd {
for (int i = 0; i < quantity; i++) { for (int i = 0; i < quantity; i++) {
int weight = template.getItemWt(); int weight = template.item_wt;
if (!cim.hasRoomInventory(weight)) { if (!cim.hasRoomInventory(weight)) {
throwbackError(pc, "Not enough room in inventory for any more of this item. " + i + " produced."); throwbackError(pc, "Not enough room in inventory for any more of this item. " + i + " produced.");
@@ -170,7 +169,6 @@ public class MakeItemCmd extends AbstractDevCmd {
Item item = new Item(templateID); Item item = new Item(templateID);
item.ownerID = pc.getObjectUUID(); item.ownerID = pc.getObjectUUID();
item.ownerType = OwnerType.PlayerCharacter; item.ownerType = OwnerType.PlayerCharacter;
item.containerType = ItemContainerType.INVENTORY;
if (numItems > 1) if (numItems > 1)
item.setNumOfItems(numItems); item.setNumOfItems(numItems);
@@ -182,11 +180,6 @@ public class MakeItemCmd extends AbstractDevCmd {
return; return;
} }
if (item == null) {
throwbackError(pc, "DB error 2: Unable to create item " + templateID + ".");
return;
}
//create prefix //create prefix
if (!prefix.isEmpty()) if (!prefix.isEmpty())
item.addPermanentEnchantmentForDev(prefix, 0); item.addPermanentEnchantmentForDev(prefix, 0);
+2 -3
View File
@@ -11,7 +11,6 @@ package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd; import engine.devcmd.AbstractDevCmd;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import java.util.ArrayList; import java.util.ArrayList;
@@ -53,8 +52,8 @@ public class PrintBankCmd extends AbstractDevCmd {
throwbackInfo(pc, "Bank for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')'); throwbackInfo(pc, "Bank for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')');
for (Item item : list) { for (Item item : list) {
CObjectTemplate template = CObjectTemplate.lookup(item.templateID); ItemTemplate template = ItemTemplate.templates.get(item.templateID);
throwbackInfo(pc, " " + template.getItemBaseName() + ", count: " + item.getNumOfItems()); throwbackInfo(pc, " " + template.item_base_name + ", count: " + item.getNumOfItems());
} }
Item gold = cim.getGoldBank(); Item gold = cim.getGoldBank();
+2 -3
View File
@@ -13,7 +13,6 @@ import engine.devcmd.AbstractDevCmd;
import engine.gameManager.ChatManager; import engine.gameManager.ChatManager;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.powers.effectmodifiers.AbstractEffectModifier;
public class PrintBonusesCmd extends AbstractDevCmd { public class PrintBonusesCmd extends AbstractDevCmd {
@@ -34,8 +33,8 @@ public class PrintBonusesCmd extends AbstractDevCmd {
if (target instanceof Item) { if (target instanceof Item) {
type = "Item"; type = "Item";
tar = (Item) target; tar = (Item) target;
CObjectTemplate template = CObjectTemplate.lookup(((Item) tar).templateID); ItemTemplate template = ItemTemplate.templates.get(((Item) tar).templateID);
name = template.getItemBaseName(); name = template.item_base_name;
} else if (target instanceof AbstractCharacter) { } else if (target instanceof AbstractCharacter) {
tar = (AbstractCharacter) target; tar = (AbstractCharacter) target;
name = ((AbstractCharacter) tar).getFirstName(); name = ((AbstractCharacter) tar).getFirstName();
+3 -3
View File
@@ -66,7 +66,7 @@ public class PrintEquipCmd extends AbstractDevCmd {
throwbackInfo(pc, "Equip for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')'); throwbackInfo(pc, "Equip for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')');
for (mbEnums.EquipSlotType slot : tarMob.charItemManager.equipped.keySet()) { for (mbEnums.EquipSlotType slot : tarMob.charItemManager.equipped.keySet()) {
Item equip = tarMob.charItemManager.equipped.get(slot); Item equip = tarMob.charItemManager.equipped.get(slot);
throwbackInfo(pc, equip.templateID + " : " + equip.template.getItemBaseName() + ", slot: " + slot); throwbackInfo(pc, equip.templateID + " : " + equip.template.item_base_name + ", slot: " + slot);
} }
return; return;
} }
@@ -76,7 +76,7 @@ public class PrintEquipCmd extends AbstractDevCmd {
throwbackInfo(pc, "Equip for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')'); throwbackInfo(pc, "Equip for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')');
for (mbEnums.EquipSlotType slot : tarMob.charItemManager.equipped.keySet()) { for (mbEnums.EquipSlotType slot : tarMob.charItemManager.equipped.keySet()) {
Item equip = tarMob.charItemManager.equipped.get(slot); Item equip = tarMob.charItemManager.equipped.get(slot);
throwbackInfo(pc, equip.templateID + " : " + equip.template.getItemBaseName() + ", slot: " + slot); throwbackInfo(pc, equip.templateID + " : " + equip.template.item_base_name + ", slot: " + slot);
} }
return; return;
} }
@@ -87,7 +87,7 @@ public class PrintEquipCmd extends AbstractDevCmd {
for (mbEnums.EquipSlotType slot : list.keySet()) { for (mbEnums.EquipSlotType slot : list.keySet()) {
Item item = list.get(slot); Item item = list.get(slot);
throwbackInfo(pc, " " + item.template.getItemBaseName() + ", slot: " + slot); throwbackInfo(pc, " " + item.template.item_base_name + ", slot: " + slot);
} }
} }
@@ -12,7 +12,6 @@ package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd; import engine.devcmd.AbstractDevCmd;
import engine.mbEnums.ItemType; import engine.mbEnums.ItemType;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
@@ -76,18 +75,18 @@ public class PrintInventoryCmd extends AbstractDevCmd {
int goldCount = 0; int goldCount = 0;
for (Item item : inventory) { for (Item item : inventory) {
CObjectTemplate template = CObjectTemplate.lookup(item.templateID); ItemTemplate template = ItemTemplate.templates.get(item.templateID);
if (item.template.getItemType().equals(ItemType.GOLD) == false) { if (item.template.item_type.equals(ItemType.GOLD) == false) {
String chargeInfo = ""; String chargeInfo = "";
int chargeMax = template.getItemInitialCharges(); int chargeMax = template.item_initial_charges;
if (chargeMax > 0) { if (chargeMax > 0) {
int charges = item.chargesRemaining; int charges = item.chargesRemaining;
chargeInfo = " charges: " + charges + '/' + chargeMax; chargeInfo = " charges: " + charges + '/' + chargeMax;
} }
throwbackInfo(pc, " " + template.getItemBaseName() + ", count: " + item.getNumOfItems() + chargeInfo); throwbackInfo(pc, " " + template.item_base_name + ", count: " + item.getNumOfItems() + chargeInfo);
} else } else
goldCount += item.getNumOfItems(); goldCount += item.getNumOfItems();
} }
+2 -3
View File
@@ -11,7 +11,6 @@ package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd; import engine.devcmd.AbstractDevCmd;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import java.util.ArrayList; import java.util.ArrayList;
@@ -51,8 +50,8 @@ public class PrintVaultCmd extends AbstractDevCmd {
ArrayList<Item> list = cim.getVault(); ArrayList<Item> list = cim.getVault();
throwbackInfo(pc, "Vault for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')'); throwbackInfo(pc, "Vault for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')');
for (Item item : list) { for (Item item : list) {
CObjectTemplate template = CObjectTemplate.lookup(item.templateID); ItemTemplate template = ItemTemplate.templates.get(item.templateID);
throwbackInfo(pc, " " + template.getItemBaseName() + ", count: " + item.getNumOfItems()); throwbackInfo(pc, " " + template.item_base_name + ", count: " + item.getNumOfItems());
} }
Item gold = cim.getGoldVault(); Item gold = cim.getGoldVault();
if (gold != null) if (gold != null)
+3 -4
View File
@@ -5,7 +5,6 @@ import engine.gameManager.LootManager;
import engine.gameManager.ZoneManager; import engine.gameManager.ZoneManager;
import engine.loot.BootySetEntry; import engine.loot.BootySetEntry;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@@ -35,10 +34,10 @@ public class SimulateBootyCmd extends AbstractDevCmd {
if (mob.bootySet != 0) { if (mob.bootySet != 0) {
for (BootySetEntry entry : LootManager._bootySetMap.get(mob.bootySet)) { for (BootySetEntry entry : LootManager._bootySetMap.get(mob.bootySet)) {
CObjectTemplate template = CObjectTemplate.lookup(entry.templateID); ItemTemplate template = ItemTemplate.templates.get(entry.templateID);
if (template != null) if (template != null)
output += "[" + entry.bootyType + "] " + template.getItemBaseName() + " [Chance] " + entry.dropChance + newline; output += "[" + entry.bootyType + "] " + template.item_base_name + " [Chance] " + entry.dropChance + newline;
} }
} }
@@ -58,7 +57,7 @@ public class SimulateBootyCmd extends AbstractDevCmd {
try { try {
mob.loadInventory(); mob.loadInventory();
for (Item lootItem : mob.charItemManager.getInventory()) { for (Item lootItem : mob.charItemManager.getInventory()) {
switch (lootItem.template.getItemType()) { switch (lootItem.template.item_type) {
case EMPLOYMENTCONTRACT: //CONTRACT case EMPLOYMENTCONTRACT: //CONTRACT
Contracts.add(lootItem); Contracts.add(lootItem);
break; break;
+13 -15
View File
@@ -22,10 +22,10 @@ import engine.mbEnums.BuildingGroup;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.net.client.msg.ErrorPopupMsg; import engine.net.client.msg.ErrorPopupMsg;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.ArrayList; import java.util.ArrayList;
@@ -200,31 +200,31 @@ public enum BuildingManager {
return false; return false;
} }
CObjectTemplate template = CObjectTemplate.lookup(1705032); // Elan Stone ItemTemplate template = ItemTemplate.templates.get(1705032); // Elan Stone
if (!player.charItemManager.hasRoomInventory(template.getItemWt())) if (!player.charItemManager.hasRoomInventory(template.item_wt))
return false; return false;
if (!ItemManager.MakeItemForPlayer(template.getTemplateId(), player, amount)) if (!ItemManager.MakeItemForPlayer(template.template_id, player, amount))
return false; return false;
shrine.setFavors(0); shrine.setFavors(0);
break; break;
case WAREHOUSE: case WAREHOUSE:
Warehouse warehouse = Warehouse.destroyedWarehouses.get(building.getObjectUUID()); City city = building.getCity();
if (city == null)
return true;
Warehouse warehouse = city.warehouse;
if (warehouse == null) if (warehouse == null)
return false; return false;
for (mbEnums.ResourceType resourceType : EnumSet.allOf(mbEnums.ResourceType.class)) { for (mbEnums.ResourceType resourceType : EnumSet.allOf(mbEnums.ResourceType.class)) {
CObjectTemplate resourceTemplate = CObjectTemplate.lookup(resourceType.templateID); if (!player.charItemManager.hasRoomInventory(resourceType.template.item_wt)) {
if (resourceTemplate == null)
continue;
if (!player.charItemManager.hasRoomInventory(resourceTemplate.getItemWt())) {
ChatManager.chatSystemInfo(player, "You can not carry any more of that item."); ChatManager.chatSystemInfo(player, "You can not carry any more of that item.");
return false; return false;
} }
@@ -242,9 +242,6 @@ public enum BuildingManager {
} }
} }
if (Warehouse.isEmpty(warehouse))
Warehouse.destroyedWarehouses.remove(building.getObjectUUID());
break; break;
} }
@@ -278,7 +275,8 @@ public enum BuildingManager {
if (building == null) if (building == null)
return; return;
if (!DbManager.BuildingQueries.updateBuildingUpgradeTime(upgradeDateTime, building, rankCost)) { Instant instant = (upgradeDateTime == null) ? null : upgradeDateTime.atZone(ZoneId.systemDefault()).toInstant();
if (!DbManager.BuildingQueries.updateBuildingUpgradeTime(instant, building, rankCost)) {
Logger.error("Failed to set upgradeTime for building " + building.getObjectUUID()); Logger.error("Failed to set upgradeTime for building " + building.getObjectUUID());
return; return;
} }
+3 -4
View File
@@ -22,7 +22,6 @@ import engine.net.client.ClientConnection;
import engine.net.client.handlers.ClientAdminCommandMsgHandler; import engine.net.client.handlers.ClientAdminCommandMsgHandler;
import engine.net.client.msg.chat.*; import engine.net.client.msg.chat.*;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.server.world.WorldServer; import engine.server.world.WorldServer;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -536,12 +535,12 @@ public enum ChatManager {
if (item != null) //Steal if (item != null) //Steal
if (success) { if (success) {
String name = ""; String name = "";
if (item.template.getItemType().equals(mbEnums.ItemType.GOLD)) if (item.template.item_type.equals(mbEnums.ItemType.GOLD))
name = amount + " gold "; name = amount + " gold ";
else { else {
String vowels = "aeiou"; String vowels = "aeiou";
CObjectTemplate template = CObjectTemplate.lookup(item.templateID); ItemTemplate template = ItemTemplate.templates.get(item.templateID);
String iName = template.getItemBaseName(); String iName = template.item_base_name;
if (iName.length() > 0) if (iName.length() > 0)
if (vowels.indexOf(iName.substring(0, 1).toLowerCase()) >= 0) if (vowels.indexOf(iName.substring(0, 1).toLowerCase()) >= 0)
name = "an " + iName + ' '; name = "an " + iName + ' ';
+30 -138
View File
@@ -14,12 +14,9 @@ import engine.jobs.AttackJob;
import engine.jobs.DeferredPowerJob; import engine.jobs.DeferredPowerJob;
import engine.mbEnums; import engine.mbEnums;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.PowerProjectileMsg;
import engine.net.client.msg.TargetedActionMsg; import engine.net.client.msg.TargetedActionMsg;
import engine.net.client.msg.UpdateStateMsg; import engine.net.client.msg.UpdateStateMsg;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.parsers.objects.RuneTemplate;
import engine.powers.DamageShield; import engine.powers.DamageShield;
import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.powers.effectmodifiers.AbstractEffectModifier;
import engine.powers.effectmodifiers.WeaponProcEffectModifier; import engine.powers.effectmodifiers.WeaponProcEffectModifier;
@@ -94,25 +91,25 @@ public enum CombatManager {
return; return;
} }
if (mainWeapon == null && offWeapon != null && !offWeapon.template.getItemSkillUsed().equals("Block")) { if (mainWeapon == null && offWeapon != null && !offWeapon.template.item_skill_used.equals("Block")) {
//swing left hand only //swing left hand only
processAttack(attacker, target, mbEnums.EquipSlotType.LHELD); processAttack(attacker, target, mbEnums.EquipSlotType.LHELD);
return; return;
} }
if (mainWeapon == null && offWeapon != null && offWeapon.template.getItemSkillUsed().equals("Block")) { if (mainWeapon == null && offWeapon != null && offWeapon.template.item_skill_used.equals("Block")) {
//no weapon equipped with a shield, punch with one hand //no weapon equipped with a shield, punch with one hand
processAttack(attacker, target, mbEnums.EquipSlotType.RHELD); processAttack(attacker, target, mbEnums.EquipSlotType.RHELD);
return; return;
} }
if (mainWeapon != null && offWeapon != null && offWeapon.template.getItemSkillUsed().equals("Block")) { if (mainWeapon != null && offWeapon != null && offWeapon.template.item_skill_used.equals("Block")) {
//one weapon equipped with a shield, swing with one hand //one weapon equipped with a shield, swing with one hand
processAttack(attacker, target, mbEnums.EquipSlotType.RHELD); processAttack(attacker, target, mbEnums.EquipSlotType.RHELD);
return; return;
} }
if (mainWeapon != null && offWeapon != null && !offWeapon.template.getItemSkillUsed().equals("Block")) { if (mainWeapon != null && offWeapon != null && !offWeapon.template.item_skill_used.equals("Block")) {
//two weapons equipped, swing both hands //two weapons equipped, swing both hands
processAttack(attacker, target, mbEnums.EquipSlotType.RHELD); processAttack(attacker, target, mbEnums.EquipSlotType.RHELD);
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter))
@@ -148,20 +145,12 @@ public enum CombatManager {
if (bonus != null) if (bonus != null)
rangeMod += bonus.getFloatPercentAll(mbEnums.ModType.WeaponRange, mbEnums.SourceType.None); rangeMod += bonus.getFloatPercentAll(mbEnums.ModType.WeaponRange, mbEnums.SourceType.None);
attackRange += engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_max_range * rangeMod; attackRange += weapon.template.item_weapon_max_range * rangeMod;
} else if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) {
//unarmed mob, add the natural attack range from its rune (0 for most melee mobs)
if (bonus != null)
rangeMod += bonus.getFloatPercentAll(mbEnums.ModType.WeaponRange, mbEnums.SourceType.None);
attackRange += getNaturalAttackRange(attacker, slot) * rangeMod;
} }
if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob))
if (((Mob) attacker).isSiege()) if (((Mob) attacker).isSiege())
attackRange = getSiegeRange((Mob) attacker); attackRange = 300;
float distanceSquared = attacker.loc.distanceSquared(target.loc); float distanceSquared = attacker.loc.distanceSquared(target.loc);
@@ -213,7 +202,7 @@ public enum CombatManager {
if (weapon != null) { if (weapon != null) {
float wepSpeed = (int) (engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_wepspeed); float wepSpeed = (int) (weapon.template.item_weapon_wepspeed);
if (weapon.getBonusPercent(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None) != 0f) //add weapon speed bonus if (weapon.getBonusPercent(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None) != 0f) //add weapon speed bonus
wepSpeed *= (1 + weapon.getBonus(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None)); wepSpeed *= (1 + weapon.getBonus(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None));
@@ -225,22 +214,6 @@ public enum CombatManager {
wepSpeed = 10; //Old was 10, but it can be reached lower with legit buffs,effects. wepSpeed = 10; //Old was 10, but it can be reached lower with legit buffs,effects.
delay = (long)wepSpeed * 100L; delay = (long)wepSpeed * 100L;
} else {
//unarmed, use the natural attack speed from the mob or race rune
float naturalSpeed = getNaturalAttackSpeed(attacker, slot);
if (naturalSpeed > 0) {
if (attacker.getBonuses() != null && attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None) != 0f) //add effects speed bonus
naturalSpeed *= (1 + attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None));
if (naturalSpeed < 10)
naturalSpeed = 10;
delay = (long) naturalSpeed * 100L;
}
} }
if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob))
@@ -259,8 +232,7 @@ public enum CombatManager {
//handle retaliate //handle retaliate
//siege engines only retaliate on damage, see AbstractCharacter.modifyHealth if (AbstractCharacter.IsAbstractCharacter(target)) {
if (AbstractCharacter.IsAbstractCharacter(target) && !(target.getObjectType().equals(mbEnums.GameObjectType.Mob) && ((Mob) target).isSiege())) {
if (((AbstractCharacter) target).combatTarget == null || !((AbstractCharacter) target).combatTarget.isAlive()) { if (((AbstractCharacter) target).combatTarget == null || !((AbstractCharacter) target).combatTarget.isAlive()) {
((AbstractCharacter) target).combatTarget = attacker; ((AbstractCharacter) target).combatTarget = attacker;
if (target.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) && ((AbstractCharacter) target).isCombat()) if (target.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) && ((AbstractCharacter) target).isCombat())
@@ -272,13 +244,13 @@ public enum CombatManager {
if (weapon != null && !attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) { if (weapon != null && !attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) {
//check if Out of Stamina //check if Out of Stamina
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
if (attacker.getStamina() < (weapon.template.getItemWt() / 3f)) { if (attacker.getStamina() < (weapon.template.item_wt / 3f)) {
//set auto attack job //set auto attack job
setAutoAttackJob(attacker, slot, delay); setAutoAttackJob(attacker, slot, delay);
return; return;
} }
} }
float stam = weapon.template.getItemWt() / 3f; float stam = weapon.template.item_wt / 3f;
stam = (stam < 1) ? 1 : stam; stam = (stam < 1) ? 1 : stam;
attacker.modifyStamina(-(stam), attacker, true); attacker.modifyStamina(-(stam), attacker, true);
} else } else
@@ -347,7 +319,7 @@ public enum CombatManager {
DispatchManager.sendToAllInRange(attacker, msg); DispatchManager.sendToAllInRange(attacker, msg);
//we need to send the animation even if the attacker misses //we need to send the animation even if the attacker misses
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon == null ? null : weapon.template, null, slot)); TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon.template, null, slot));
DispatchManager.sendToAllInRange(target, cmm); DispatchManager.sendToAllInRange(target, cmm);
//set auto attack job //set auto attack job
@@ -387,7 +359,7 @@ public enum CombatManager {
DispatchManager.dispatchMsgToInterestArea(target, msg, mbEnums.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); DispatchManager.dispatchMsgToInterestArea(target, msg, mbEnums.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
//we need to send the animation even if the attacker misses //we need to send the animation even if the attacker misses
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon == null ? null : weapon.template, null, slot)); TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon.template, null, slot));
DispatchManager.sendToAllInRange(target, cmm); DispatchManager.sendToAllInRange(target, cmm);
//set auto attack job //set auto attack job
setAutoAttackJob(attacker, slot, delay); setAutoAttackJob(attacker, slot, delay);
@@ -418,7 +390,7 @@ public enum CombatManager {
if (((Mob) attacker).isSiege()) if (((Mob) attacker).isSiege())
damageType = mbEnums.DamageType.SIEGE; damageType = mbEnums.DamageType.SIEGE;
} else { } else {
damageType = engine.parsers.objects.ItemTemplate.getWeapon(attacker.charItemManager.getEquipped().get(slot).templateID).weapon_damage.get(0).damage_type; damageType = (mbEnums.DamageType) attacker.charItemManager.getEquipped().get(slot).template.item_weapon_damage.keySet().toArray()[0];
} }
//get resists //get resists
@@ -475,7 +447,7 @@ public enum CombatManager {
if (resists.immuneTo(damageType)) { if (resists.immuneTo(damageType)) {
//set auto attack job //set auto attack job
//we need to send the animation even if the attacker misses //we need to send the animation even if the attacker misses
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon == null ? null : weapon.template, null, slot)); TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon.template, null, slot));
DispatchManager.sendToAllInRange(target, cmm); DispatchManager.sendToAllInRange(target, cmm);
setAutoAttackJob(attacker, slot, delay); setAutoAttackJob(attacker, slot, delay);
return; return;
@@ -507,15 +479,6 @@ public enum CombatManager {
} }
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) damage, attackAnim); TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) damage, attackAnim);
DispatchManager.sendToAllInRange(target, cmm); DispatchManager.sendToAllInRange(target, cmm);
//siege projectile is sent once per hit, not per AI pulse
if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob) && ((Mob) attacker).isSiege()
&& target.getObjectType().equals(mbEnums.GameObjectType.Building)) {
PowerProjectileMsg ppm = new PowerProjectileMsg(attacker, target);
ppm.setRange(50);
DispatchManager.dispatchMsgToInterestArea(attacker, ppm, mbEnums.DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
}
} }
} }
@@ -579,14 +542,13 @@ public enum CombatManager {
target.setCombatTarget(attacker); target.setCombatTarget(attacker);
} }
public static int getSwingAnimation(CObjectTemplate wb, DeferredPowerJob dpj, mbEnums.EquipSlotType slot) { public static int getSwingAnimation(ItemTemplate wb, DeferredPowerJob dpj, mbEnums.EquipSlotType slot) {
//No weapon, return default animation //No weapon, return default animation
if (wb == null) if (wb == null)
return 75; return 75;
int token; int token;
engine.parsers.objects.ItemTemplate.Weapon weapon = engine.parsers.objects.ItemTemplate.getWeapon(wb.getTemplateId());
if (dpj != null) { if (dpj != null) {
@@ -597,7 +559,7 @@ public enum CombatManager {
} }
//Item has no equipment slots and should not try to return an animation, return default instead //Item has no equipment slots and should not try to return an animation, return default instead
if (wb.getItemEqSlotsOr().isEmpty()) { if (wb.item_eq_slots_or == null || wb.item_eq_slots_or.isEmpty()) {
return 75; return 75;
} }
@@ -606,18 +568,18 @@ public enum CombatManager {
int random; int random;
//Item can only be equipped in one slot, return animation for that slot //Item can only be equipped in one slot, return animation for that slot
if (wb.getItemEqSlotsOr().size() == 1) { if (wb.item_eq_slots_or.size() == 1) {
if (wb.getItemEqSlotsOr().iterator().next().equals(mbEnums.EquipSlotType.RHELD)) { if (wb.item_eq_slots_or.iterator().next().equals(mbEnums.EquipSlotType.RHELD)) {
anim = weapon.weapon_attack_anim_right.get(0)[0]; anim = wb.weapon_attack_anim_right.get(0)[0];
if (dpj != null) { if (dpj != null) {
random = ThreadLocalRandom.current().nextInt(weapon.weapon_attack_anim_right.size()); random = ThreadLocalRandom.current().nextInt(wb.weapon_attack_anim_right.size());
anim = weapon.weapon_attack_anim_right.get(random)[0]; anim = wb.weapon_attack_anim_right.get(random)[0];
} }
} else { } else {
anim = weapon.weapon_attack_anim_left.get(0)[0]; anim = wb.weapon_attack_anim_left.get(0)[0];
if (dpj != null) { if (dpj != null) {
random = ThreadLocalRandom.current().nextInt(weapon.weapon_attack_anim_left.size()); random = ThreadLocalRandom.current().nextInt(wb.weapon_attack_anim_left.size());
anim = weapon.weapon_attack_anim_left.get(random)[0]; anim = wb.weapon_attack_anim_left.get(random)[0];
} }
} }
return anim; return anim;
@@ -625,16 +587,16 @@ public enum CombatManager {
//Item can be equipped in either hand, and should have animation sets for each hand //Item can be equipped in either hand, and should have animation sets for each hand
if (slot.equals(mbEnums.EquipSlotType.RHELD)) { if (slot.equals(mbEnums.EquipSlotType.RHELD)) {
anim = weapon.weapon_attack_anim_right.get(0)[0]; anim = wb.weapon_attack_anim_right.get(0)[0];
if (dpj != null) { if (dpj != null) {
random = ThreadLocalRandom.current().nextInt(weapon.weapon_attack_anim_right.size()); random = ThreadLocalRandom.current().nextInt(wb.weapon_attack_anim_right.size());
anim = weapon.weapon_attack_anim_right.get(random)[0]; anim = wb.weapon_attack_anim_right.get(random)[0];
} }
} else { } else {
anim = weapon.weapon_attack_anim_left.get(0)[0]; anim = wb.weapon_attack_anim_left.get(0)[0];
if (dpj != null) { if (dpj != null) {
random = ThreadLocalRandom.current().nextInt(weapon.weapon_attack_anim_left.size()); random = ThreadLocalRandom.current().nextInt(wb.weapon_attack_anim_left.size());
anim = weapon.weapon_attack_anim_left.get(random)[0]; anim = wb.weapon_attack_anim_left.get(random)[0];
} }
} }
return anim; return anim;
@@ -674,76 +636,6 @@ public enum CombatManager {
} }
public static float getNaturalAttackSpeed(AbstractCharacter attacker, mbEnums.EquipSlotType slot) {
// Returns the rune natural attack speed (x100 ms) for this hand, or 0 if the rune has none.
float[] attack = getNaturalAttack(attacker, slot);
if (attack == null || attack.length < 1)
return 0;
return attack[0];
}
public static float getNaturalAttackRange(AbstractCharacter attacker, mbEnums.EquipSlotType slot) {
// Returns the rune natural attack range for this hand, or 0 if the rune has none.
float[] attack = getNaturalAttack(attacker, slot);
if (attack == null || attack.length < 2)
return 0;
return attack[1];
}
public static float getSiegeRange(Mob siegeEngine) {
// Siege engines use the range from their rune natural attack (350 for all three), 300 if the rune has none.
float range = getNaturalAttackRange(siegeEngine, mbEnums.EquipSlotType.RHELD);
if (range <= 0)
return 300;
return range;
}
public static float[] getNaturalAttack(AbstractCharacter attacker, mbEnums.EquipSlotType slot) {
// Returns the rune natural attack entry for this hand, or null if the rune has none.
// Mobs use their mobbase rune, players use their race rune.
int runeID;
RuneTemplate rune;
int hand = slot.equals(mbEnums.EquipSlotType.LHELD) ? 2 : 1;
switch (attacker.getObjectType()) {
case Mob:
runeID = ((Mob) attacker).loadID;
break;
case PlayerCharacter:
runeID = ((PlayerCharacter) attacker).getRaceID();
break;
default:
return null;
}
rune = RuneTemplate._runes.get(runeID);
if (rune == null || rune.rune_naturalattacks.isEmpty())
return null;
for (float[] attack : rune.rune_naturalattacks)
if (attack.length > 3 && (int) attack[3] == hand)
return attack;
// No entry for this hand, fall back to the first natural attack
return rune.rune_naturalattacks.get(0);
}
public static int calculatePetDamage(AbstractCharacter agent) { public static int calculatePetDamage(AbstractCharacter agent) {
//damage calc for pet //damage calc for pet
float range; float range;
+8 -1
View File
@@ -75,7 +75,6 @@ public enum ConfigManager {
// Mobile AI modifiers // Mobile AI modifiers
MB_AI_CAST_FREQUENCY, MB_AI_CAST_FREQUENCY,
MB_AI_AGGRO_RANGE, MB_AI_AGGRO_RANGE,
MB_MINION_SPAWN_TIME,
//drop rates //drop rates
MB_NORMAL_EXP_RATE, MB_NORMAL_EXP_RATE,
@@ -166,6 +165,14 @@ public enum ConfigManager {
regex.put(MB_LOGIN_FNAME_REGEX, Pattern.compile(MB_LOGIN_FNAME_REGEX.getValue())); regex.put(MB_LOGIN_FNAME_REGEX, Pattern.compile(MB_LOGIN_FNAME_REGEX.getValue()));
Logger.info("Loading WPAK data");
// *** Needs powermanager collection
// defined before activation.
// EffectsParser.parseWpakFile();
// PowersParser.parseWpakFile();
// PowerActionParser.parseWpakFile();
return true; return true;
} }
@@ -101,7 +101,6 @@ public enum DevCmdManager {
DevCmdManager.registerDevCmd(new SetAdminRuneCmd()); DevCmdManager.registerDevCmd(new SetAdminRuneCmd());
DevCmdManager.registerDevCmd(new SetInvulCmd()); DevCmdManager.registerDevCmd(new SetInvulCmd());
DevCmdManager.registerDevCmd(new MakeItemCmd()); DevCmdManager.registerDevCmd(new MakeItemCmd());
DevCmdManager.registerDevCmd(new FillCmd());
DevCmdManager.registerDevCmd(new SetSubRaceCmd()); DevCmdManager.registerDevCmd(new SetSubRaceCmd());
// Admin // Admin
+9 -16
View File
@@ -15,8 +15,8 @@ import engine.mbEnums;
import engine.net.client.msg.ItemProductionMsg; import engine.net.client.msg.ItemProductionMsg;
import engine.objects.City; import engine.objects.City;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.ItemTemplate;
import engine.objects.NPC; import engine.objects.NPC;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -49,9 +49,6 @@ public enum ForgeManager implements Runnable {
public static final ConcurrentHashMap<NPC, ConcurrentHashMap.KeySetView<WorkOrder, Boolean>> vendorWorkOrderLookup = new ConcurrentHashMap<>(); public static final ConcurrentHashMap<NPC, ConcurrentHashMap.KeySetView<WorkOrder, Boolean>> vendorWorkOrderLookup = new ConcurrentHashMap<>();
public static final ConcurrentHashMap<Item, WorkOrder> itemWorkOrderLookup = new ConcurrentHashMap<>(); public static final ConcurrentHashMap<Item, WorkOrder> itemWorkOrderLookup = new ConcurrentHashMap<>();
// Server-only data from static_vendor_items; the client templates have no mod table.
public static HashMap<Integer, Integer> vendorModTables = new HashMap<>();
public static void start() { public static void start() {
Thread forgeManager; Thread forgeManager;
@@ -225,12 +222,12 @@ public enum ForgeManager implements Runnable {
// Calculate production cost for a single run of the workOrder // Calculate production cost for a single run of the workOrder
HashMap<mbEnums.ResourceType, Integer> production_cost = new HashMap<>(); HashMap<mbEnums.ResourceType, Integer> production_cost = new HashMap<>();
CObjectTemplate template = CObjectTemplate.lookup(workOrder.templateID); ItemTemplate template = ItemTemplate.templates.get(workOrder.templateID);
// Add gold and resource costs from template // Add gold and resource costs from template
production_cost.put(mbEnums.ResourceType.GOLD, template.getItemValue()); production_cost.put(mbEnums.ResourceType.GOLD, template.item_value);
production_cost.putAll(template.getItemResourceCosts()); production_cost.putAll(template.item_resource_cost);
// Calculate cost of prefix and suffix // Calculate cost of prefix and suffix
@@ -251,8 +248,8 @@ public enum ForgeManager implements Runnable {
// Create new virtual item from specified template // Create new virtual item from specified template
ItemTemplate template = ItemTemplate.templates.get(workOrder.templateID);
Item forgedItem = new Item(workOrder.templateID); Item forgedItem = new Item(workOrder.templateID);
int modTable = getVendorModTable(workOrder.templateID);
// forgedItem gets a negative id; a virtual item which is not persisted // forgedItem gets a negative id; a virtual item which is not persisted
@@ -267,13 +264,13 @@ public enum ForgeManager implements Runnable {
// Assign a prefix and suffix to this item if random rolled // Assign a prefix and suffix to this item if random rolled
if (workOrder.prefixToken == 0 && workOrder.vendor.getItemModTable().contains(modTable)) if (workOrder.prefixToken == 0 && workOrder.vendor.getItemModTable().contains((template.modTable)))
forgedItem.prefixToken = calcRandomMod(workOrder.vendor, mbEnums.ItemModType.PREFIX, modTable); forgedItem.prefixToken = calcRandomMod(workOrder.vendor, mbEnums.ItemModType.PREFIX, template.modTable);
else else
forgedItem.prefixToken = workOrder.prefixToken; forgedItem.prefixToken = workOrder.prefixToken;
if (workOrder.suffixToken == 0 && workOrder.vendor.getItemModTable().contains(modTable)) if (workOrder.suffixToken == 0 && workOrder.vendor.getItemModTable().contains((template.modTable)))
forgedItem.suffixToken = calcRandomMod(workOrder.vendor, mbEnums.ItemModType.SUFFIX, modTable); forgedItem.suffixToken = calcRandomMod(workOrder.vendor, mbEnums.ItemModType.SUFFIX, template.modTable);
else else
forgedItem.suffixToken = workOrder.suffixToken; forgedItem.suffixToken = workOrder.suffixToken;
@@ -367,10 +364,6 @@ public enum ForgeManager implements Runnable {
DbManager.WarehouseQueries.WRITE_WORKORDER(workOrder); DbManager.WarehouseQueries.WRITE_WORKORDER(workOrder);
} }
public static int getVendorModTable(int templateID) {
return vendorModTables.getOrDefault(templateID, 0);
}
public static int calcRandomMod(NPC vendor, mbEnums.ItemModType itemModType, int modTable) { public static int calcRandomMod(NPC vendor, mbEnums.ItemModType itemModType, int modTable) {
// Random prefix or suffix token based on item.template.modtable // Random prefix or suffix token based on item.template.modtable
+1 -1
View File
@@ -307,7 +307,7 @@ public enum GroupManager {
return false; return false;
} }
if (!item.template.getItemType().equals(mbEnums.ItemType.GOLD)) //only split goldItem if (!item.template.item_type.equals(mbEnums.ItemType.GOLD)) //only split goldItem
return false; return false;
Group group = getGroup(pc); Group group = getGroup(pc);
+5 -5
View File
@@ -16,7 +16,7 @@ import engine.net.client.ClientConnection;
import engine.net.client.msg.guild.AcceptInviteToGuildMsg; import engine.net.client.msg.guild.AcceptInviteToGuildMsg;
import engine.net.client.msg.guild.GuildInfoMsg; import engine.net.client.msg.guild.GuildInfoMsg;
import engine.objects.*; import engine.objects.*;
import org.joda.time.DateTime; import java.time.Instant;
public enum GuildManager { public enum GuildManager {
@@ -67,8 +67,8 @@ public enum GuildManager {
return false; return false;
if (playerCharacter.getGuild() != null && !playerCharacter.getGuild().isEmptyGuild()) { if (playerCharacter.getGuild() != null && !playerCharacter.getGuild().isEmptyGuild()) {
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(playerCharacter.getGuildUUID(), playerCharacter, DateTime.now(), GuildHistoryType.LEAVE)) { if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(playerCharacter.getGuildUUID(), playerCharacter, Instant.now(), GuildHistoryType.LEAVE)) {
GuildHistory guildHistory = new GuildHistory(playerCharacter.getGuildUUID(), playerCharacter.getGuild().getName(), DateTime.now(), GuildHistoryType.LEAVE); GuildHistory guildHistory = new GuildHistory(playerCharacter.getGuildUUID(), playerCharacter.getGuild().getName(), Instant.now(), GuildHistoryType.LEAVE);
playerCharacter.getGuildHistory().add(guildHistory); playerCharacter.getGuildHistory().add(guildHistory);
} }
} }
@@ -90,8 +90,8 @@ public enum GuildManager {
dispatch = Dispatch.borrow(playerCharacter, msg); dispatch = Dispatch.borrow(playerCharacter, msg);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
} }
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(guild.getObjectUUID(), playerCharacter, DateTime.now(), historyType)) { if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(guild.getObjectUUID(), playerCharacter, Instant.now(), historyType)) {
GuildHistory guildHistory = new GuildHistory(guild.getObjectUUID(), guild.getName(), DateTime.now(), historyType); GuildHistory guildHistory = new GuildHistory(guild.getObjectUUID(), guild.getName(), Instant.now(), historyType);
playerCharacter.getGuildHistory().add(guildHistory); playerCharacter.getGuildHistory().add(guildHistory);
} }
+54 -35
View File
@@ -2,7 +2,6 @@ package engine.gameManager;
import engine.mbEnums; import engine.mbEnums;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -22,46 +21,66 @@ public enum ItemManager {
public static final AtomicInteger lastNegativeID = new AtomicInteger(0); public static final AtomicInteger lastNegativeID = new AtomicInteger(0);
// restrict true: the set is a blacklist; false: a whitelist. An empty set allows everyone.
public static Boolean ValidRace(Item item, mbEnums.MonsterType race) { public static Boolean ValidRace(Item item, mbEnums.MonsterType race) {
EnumSet<mbEnums.MonsterType> races = item.template.getItemRaceReq(); if (item.template.item_race_req.isEmpty() && item.template.item_race_res.isEmpty())
boolean restrict = item.template.getItemRaceReqRestrict();
if (races.isEmpty())
return true; return true;
return races.contains(race) != restrict; if (item.template.item_race_req.isEmpty() == false)
if (item.template.item_race_req.contains(race))
return true;
if (item.template.item_race_res.isEmpty() == false)
if (item.template.item_race_res.contains(race) == false)
return true;
return false;
} }
public static Boolean ValidClass(Item item, mbEnums.ClassType base, mbEnums.ClassType profession) { public static Boolean ValidClass(Item item, mbEnums.ClassType base, mbEnums.ClassType profession) {
EnumSet<mbEnums.ClassType> classes = item.template.getItemClassReq(); // Early exit if no entry
boolean restrict = item.template.getItemClassReqRestrict();
boolean listed;
if (classes.isEmpty()) if (item.template.item_class_req.isEmpty() && item.template.item_class_res.isEmpty())
return true; return true;
listed = classes.contains(base) || classes.contains(profession); if (item.template.item_class_req.isEmpty() == false)
if (item.template.item_class_req.contains(base) || item.template.item_class_req.contains(profession))
return true;
return listed != restrict; if (item.template.item_class_res.isEmpty() == false)
if (item.template.item_class_res.contains(base) == false && item.template.item_class_res.contains(profession) == false)
return true;
return false;
} }
public static Boolean ValidDiscipline(Item item, EnumSet<mbEnums.DisciplineType> discs) { public static Boolean ValidDiscipline(Item item, EnumSet<mbEnums.DisciplineType> discs) {
EnumSet<mbEnums.DisciplineType> disciplines = item.template.getItemDiscReq(); // Early exit if no entry
boolean restrict = item.template.getItemDiscReqRestrict();
EnumSet<mbEnums.DisciplineType> workSet;
if (disciplines.isEmpty()) if (item.template.item_disc_req.isEmpty() && item.template.item_disc_res.isEmpty())
return true; return true;
workSet = EnumSet.copyOf(discs); EnumSet<mbEnums.DisciplineType> workSet = EnumSet.copyOf(discs);
workSet.retainAll(disciplines);
return workSet.isEmpty() == restrict; if (item.template.item_disc_req.isEmpty() == false) {
workSet.retainAll(item.template.item_disc_req);
if (workSet.isEmpty() == false)
return true;
}
if (item.template.item_disc_res.isEmpty() == false) {
workSet.retainAll(item.template.item_disc_res);
if (workSet.isEmpty() == false)
return true;
}
return false;
} }
public static Boolean canCharacterEquip(Item item, AbstractCharacter character) { public static Boolean canCharacterEquip(Item item, AbstractCharacter character) {
@@ -72,12 +91,12 @@ public enum ItemManager {
CharacterSkill characterSkill; CharacterSkill characterSkill;
if (item.template.getItemSkillReq().isEmpty()) if (item.template.item_skill_required.isEmpty())
return true; return true;
for (String skillRequired : item.template.getItemSkillReq().keySet()) { for (String skillRequired : item.template.item_skill_required.keySet()) {
int required_value = item.template.getItemSkillReq().get(skillRequired); int required_value = item.template.item_skill_required.get(skillRequired);
characterSkill = skills.get(skillRequired); characterSkill = skills.get(skillRequired);
if (characterSkill == null) if (characterSkill == null)
@@ -93,31 +112,31 @@ public enum ItemManager {
public static boolean isTwoHanded(Item item) { public static boolean isTwoHanded(Item item) {
if (!item.template.getItemType().equals(mbEnums.ItemType.WEAPON)) if (!item.template.item_type.equals(mbEnums.ItemType.WEAPON))
return false; return false;
return item.template.getItemEqSlotsAnd().containsAll(EnumSet.of(mbEnums.EquipSlotType.LHELD, mbEnums.EquipSlotType.RHELD)); return item.template.item_eq_slots_and.contains(EnumSet.of(mbEnums.EquipSlotType.LHELD, mbEnums.EquipSlotType.RHELD));
} }
public static boolean isTwoHanded(CObjectTemplate template) { public static boolean isTwoHanded(ItemTemplate template) {
if (!template.getItemType().equals(mbEnums.ItemType.WEAPON)) if (!template.item_type.equals(mbEnums.ItemType.WEAPON))
return false; return false;
return template.getItemEqSlotsAnd().containsAll(EnumSet.of(mbEnums.EquipSlotType.LHELD, mbEnums.EquipSlotType.RHELD)); return template.item_eq_slots_and.contains(EnumSet.of(mbEnums.EquipSlotType.LHELD, mbEnums.EquipSlotType.RHELD));
} }
public static boolean isShield(Item item) { public static boolean isShield(Item item) {
if (item.template.getItemSkillReq().containsKey("Block")) if (item.template.item_skill_required.containsKey("Block"))
return true; return true;
return false; return false;
} }
public static boolean isShield(CObjectTemplate template) { public static boolean isShield(ItemTemplate template) {
if (template.getItemSkillReq().containsKey("Block")) if (template.item_skill_required.containsKey("Block"))
return true; return true;
return false; return false;
@@ -131,7 +150,7 @@ public enum ItemManager {
return false; return false;
//Item not valid for slot //Item not valid for slot
if (item.template.getItemEqSlotsOr().contains(slot) == false) if (item.template.item_eq_slots_or.contains(slot) == false)
return false; return false;
// Slot is taken // Slot is taken
@@ -146,7 +165,7 @@ public enum ItemManager {
(slot == mbEnums.EquipSlotType.RHELD && equipped.get(mbEnums.EquipSlotType.LHELD) != null))) (slot == mbEnums.EquipSlotType.RHELD && equipped.get(mbEnums.EquipSlotType.LHELD) != null)))
return false; return false;
if (item.template.getItemType().equals(mbEnums.ItemType.WEAPON)) if (item.template.item_type.equals(mbEnums.ItemType.WEAPON))
if (equipped.get(slot) != null && equipped.get(slot).equals(item) == false) if (equipped.get(slot) != null && equipped.get(slot).equals(item) == false)
return false; return false;
@@ -178,7 +197,7 @@ public enum ItemManager {
//players can't wear 0 value items. //players can't wear 0 value items.
return item.template.getItemValue() != 0 || Kit.IsNoobGear(item.templateID); return item.template.item_value != 0 || Kit.IsNoobGear(item.templateID);
} }
+8 -9
View File
@@ -13,7 +13,6 @@ import engine.mbEnums;
import engine.net.client.msg.ErrorPopupMsg; import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.chat.ChatSystemMsg; import engine.net.client.msg.chat.ChatSystemMsg;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.util.ArrayList; import java.util.ArrayList;
@@ -92,8 +91,8 @@ public enum LootManager {
//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
for (Item item : mob.getInventory()) { for (Item item : mob.getInventory()) {
if ((item.templateID > 2499 && item.templateID <= 3050) || item.template.getItemBaseName().toLowerCase().contains("of the gods")) { if ((item.templateID > 2499 && item.templateID <= 3050) || item.template.item_base_name.toLowerCase().contains("of the gods")) {
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().zoneName + " has found the " + item.template.getItemBaseName() + ". Are you tough enough to take it?"); ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().zoneName + " has found the " + item.template.item_base_name + ". Are you tough enough to take it?");
chatMsg.setMessageType(10); chatMsg.setMessageType(10);
chatMsg.setChannel(mbEnums.ChatChannelType.SYSTEM.getChannelID()); chatMsg.setChannel(mbEnums.ChatChannelType.SYSTEM.getChannelID());
DispatchManager.dispatchMsgToAll(chatMsg); DispatchManager.dispatchMsgToAll(chatMsg);
@@ -180,12 +179,12 @@ public enum LootManager {
if (itemUUID == 0) if (itemUUID == 0)
return null; return null;
if (CObjectTemplate.lookup(itemUUID).getItemType().equals(mbEnums.ItemType.RESOURCE)) { if (ItemTemplate.templates.get(itemUUID).item_type.equals(mbEnums.ItemType.RESOURCE)) {
int amount = ThreadLocalRandom.current().nextInt(tableRow.minSpawn, tableRow.maxSpawn + 1); int amount = ThreadLocalRandom.current().nextInt(tableRow.minSpawn, tableRow.maxSpawn + 1);
return new MobLoot(mob, CObjectTemplate.lookup(itemUUID), amount, false); return new MobLoot(mob, ItemTemplate.templates.get(itemUUID), amount, false);
} }
outItem = new MobLoot(mob, CObjectTemplate.lookup(itemUUID), false); outItem = new MobLoot(mob, ItemTemplate.templates.get(itemUUID), false);
if (selectedRow.pModTable != 0) if (selectedRow.pModTable != 0)
try { try {
@@ -375,7 +374,7 @@ public enum LootManager {
if (chanceRoll > bse.dropChance) if (chanceRoll > bse.dropChance)
return; return;
MobLoot lootItem = new MobLoot(mob, CObjectTemplate.lookup(bse.templateID), true); MobLoot lootItem = new MobLoot(mob, ItemTemplate.templates.get(bse.templateID), true);
if (lootItem != null) if (lootItem != null)
mob.charItemManager.addItemToInventory(lootItem); mob.charItemManager.addItemToInventory(lootItem);
@@ -423,14 +422,14 @@ 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, CObjectTemplate.lookup(selectedItem.templateID), 1, false); MobLoot winnings = new MobLoot(playerCharacter, ItemTemplate.templates.get(selectedItem.templateID), 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 old the item
if (itemMan.hasRoomInventory(winnings.template.getItemWt()) == false) { if (itemMan.hasRoomInventory(winnings.template.item_wt) == false) {
ErrorPopupMsg.sendErrorPopup(playerCharacter, 21); ErrorPopupMsg.sendErrorPopup(playerCharacter, 21);
return; return;
} }
+22 -32
View File
@@ -19,14 +19,12 @@ import engine.net.client.ClientConnection;
import engine.net.client.msg.ErrorPopupMsg; import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.PetMsg; import engine.net.client.msg.PetMsg;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import engine.powers.RuneSkillAdjustEntry; import engine.powers.RuneSkillAdjustEntry;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@@ -317,26 +315,26 @@ public enum NPCManager {
//has main hand weapon //has main hand weapon
Item weapon = guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD); Item weapon = guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD);
if (engine.parsers.objects.ItemTemplate._items.get(weapon.templateID).item_primary_attr == mbEnums.AttributeType.Strength) if (weapon.template.item_primary_attr.equals(mbEnums.AttributeType.Strength))
primaryStat = guard.getStatStrCurrent(); primaryStat = guard.getStatStrCurrent();
else else
primaryStat = guard.getStatDexCurrent(); primaryStat = guard.getStatDexCurrent();
guard.minDamageHandOne = (int) ((guard.mobBase.getDamageMin() + engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_damage.get(0).damage_min) * rankModifier) + primaryStat; guard.minDamageHandOne = (int) ((guard.mobBase.getDamageMin() + weapon.template.item_weapon_damage.values().iterator().next()[0]) * rankModifier) + primaryStat;
guard.maxDamageHandOne = (int) ((guard.mobBase.getDamageMax() + engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_damage.get(0).damage_max) * rankModifier) + primaryStat; guard.maxDamageHandOne = (int) ((guard.mobBase.getDamageMax() + weapon.template.item_weapon_damage.values().iterator().next()[1]) * rankModifier) + primaryStat;
guard.speedHandOne = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_wepspeed; guard.speedHandOne = weapon.template.item_weapon_wepspeed;
guard.rangeHandOne = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_max_range; guard.rangeHandOne = weapon.template.item_weapon_max_range;
} else if (guard.charItemManager.equipped.containsKey(mbEnums.EquipSlotType.LHELD) && !ItemManager.isShield(guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template)) { } else if (guard.charItemManager.equipped.containsKey(mbEnums.EquipSlotType.LHELD) && !ItemManager.isShield(guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template)) {
//has off hand weapon //has off hand weapon
Item weapon = guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD); Item weapon = guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD);
if (engine.parsers.objects.ItemTemplate._items.get(weapon.templateID).item_primary_attr == mbEnums.AttributeType.Strength) if (weapon.template.item_primary_attr.equals(mbEnums.AttributeType.Strength))
primaryStat = guard.getStatStrCurrent(); primaryStat = guard.getStatStrCurrent();
else else
primaryStat = guard.getStatDexCurrent(); primaryStat = guard.getStatDexCurrent();
guard.minDamageHandOne = (int) ((guard.mobBase.getDamageMin() + engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_damage.get(0).damage_min) * rankModifier) + primaryStat; guard.minDamageHandOne = (int) ((guard.mobBase.getDamageMin() + weapon.template.item_weapon_damage.values().iterator().next()[0]) * rankModifier) + primaryStat;
guard.maxDamageHandOne = (int) ((guard.mobBase.getDamageMax() + engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_damage.get(0).damage_max) * rankModifier) + primaryStat; guard.maxDamageHandOne = (int) ((guard.mobBase.getDamageMax() + weapon.template.item_weapon_damage.values().iterator().next()[1]) * rankModifier) + primaryStat;
guard.speedHandOne = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_wepspeed; guard.speedHandOne = weapon.template.item_weapon_wepspeed;
guard.rangeHandOne = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_max_range; guard.rangeHandOne = weapon.template.item_weapon_max_range;
} else { } else {
primaryStat = guard.getStatStrCurrent(); primaryStat = guard.getStatStrCurrent();
guard.minDamageHandOne = (int) ((guard.mobBase.getDamageMin()) * rankModifier) + primaryStat; guard.minDamageHandOne = (int) ((guard.mobBase.getDamageMin()) * rankModifier) + primaryStat;
@@ -354,8 +352,8 @@ public enum NPCManager {
int baseDef = guard.mobBase.getDefenseRating(); int baseDef = guard.mobBase.getDefenseRating();
int armorDefense = 0; int armorDefense = 0;
for (Item equipped : guard.charItemManager.equipped.values()) for (Item equipped : guard.charItemManager.equipped.values())
if (equipped.template.getItemType().equals(mbEnums.ItemType.ARMOR) || ItemManager.isShield(equipped.template)) if (equipped.template.item_type.equals(mbEnums.ItemType.ARMOR) || ItemManager.isShield(equipped.template))
armorDefense += engine.parsers.objects.ItemTemplate._items.get(equipped.templateID).item_defense_rating; armorDefense += equipped.template.item_defense_rating;
guard.defenseRating = dexterity + baseDef + armorDefense; guard.defenseRating = dexterity + baseDef + armorDefense;
} }
@@ -363,9 +361,9 @@ public enum NPCManager {
int strength = guard.getStatStrCurrent(); int strength = guard.getStatStrCurrent();
int baseAtr = guard.mobBase.getAttackRating(); int baseAtr = guard.mobBase.getAttackRating();
if (guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD) != null) if (guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD) != null)
guard.atrHandOne = baseAtr + (int) ((strength * 0.5f) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD).template.getItemSkillReq().values().toArray()[0] * 4) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD).template.getItemSkillReq().values().toArray()[0] * 3)); guard.atrHandOne = baseAtr + (int) ((strength * 0.5f) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD).template.item_skill_required.values().toArray()[0] * 4) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD).template.item_skill_required.values().toArray()[0] * 3));
else if (guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD) != null && !ItemManager.isShield(guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template)) else if (guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD) != null && !ItemManager.isShield(guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template))
guard.atrHandTwo = baseAtr + (int) ((strength * 0.5f) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template.getItemSkillReq().values().toArray()[0] * 4) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template.getItemSkillReq().values().toArray()[0] * 3)); guard.atrHandTwo = baseAtr + (int) ((strength * 0.5f) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template.item_skill_required.values().toArray()[0] * 4) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template.item_skill_required.values().toArray()[0] * 3));
else else
guard.atrHandOne = baseAtr; guard.atrHandOne = baseAtr;
} }
@@ -440,17 +438,14 @@ public enum NPCManager {
public static void applyEquipmentResists(Mob mob) { public static void applyEquipmentResists(Mob mob) {
EnumMap<mbEnums.DamageType, Float> armorResists;
if (mob.charItemManager.equipped.isEmpty()) if (mob.charItemManager.equipped.isEmpty())
return; return;
for (Item equipped : mob.charItemManager.equipped.values()) { for (Item equipped : mob.charItemManager.equipped.values()) {
if (equipped.template.getItemType().equals(mbEnums.ItemType.ARMOR)) { if (equipped.template.item_type.equals(mbEnums.ItemType.ARMOR)) {
armorResists = equipped.template.getCombatAttackResist(); mob.resists.setResist(mbEnums.DamageType.SLASHING, mob.resists.getResist(mbEnums.DamageType.SLASHING, 0) + equipped.template.combat_attack_resist.get("SLASHING"));
mob.resists.setResist(mbEnums.DamageType.SLASHING, mob.resists.getResist(mbEnums.DamageType.SLASHING, 0) + armorResists.getOrDefault(mbEnums.DamageType.SLASHING, 0f)); mob.resists.setResist(mbEnums.DamageType.CRUSHING, mob.resists.getResist(mbEnums.DamageType.CRUSHING, 0) + equipped.template.combat_attack_resist.get("CRUSHING"));
mob.resists.setResist(mbEnums.DamageType.CRUSHING, mob.resists.getResist(mbEnums.DamageType.CRUSHING, 0) + armorResists.getOrDefault(mbEnums.DamageType.CRUSHING, 0f)); mob.resists.setResist(mbEnums.DamageType.PIERCING, mob.resists.getResist(mbEnums.DamageType.PIERCING, 0) + equipped.template.combat_attack_resist.get("PIERCING"));
mob.resists.setResist(mbEnums.DamageType.PIERCING, mob.resists.getResist(mbEnums.DamageType.PIERCING, 0) + armorResists.getOrDefault(mbEnums.DamageType.PIERCING, 0f));
} }
} }
} }
@@ -471,7 +466,7 @@ public enum NPCManager {
if (skillBase == null) if (skillBase == null)
continue; continue;
if (entry.level <= mob.level) if (entry.level <= mob.level)
if (mob.skills.containsKey(entry.skill_type) == false) if (mob.skills.containsKey(entry.name) == false)
mob.skills.put(entry.skill_type, new CharacterSkill(skillBase, mob, entry.rank)); mob.skills.put(entry.skill_type, new CharacterSkill(skillBase, mob, entry.rank));
else else
mob.skills.put(entry.skill_type, new CharacterSkill(skillBase, mob, entry.rank + mob.skills.get(entry.skill_type).getNumTrains())); mob.skills.put(entry.skill_type, new CharacterSkill(skillBase, mob, entry.rank + mob.skills.get(entry.skill_type).getNumTrains()));
@@ -485,11 +480,6 @@ public enum NPCManager {
npc.runes.add(shopkeeper); npc.runes.add(shopkeeper);
if (NPCManager._runeSetMap.containsKey(npc.runeSetID)) { if (NPCManager._runeSetMap.containsKey(npc.runeSetID)) {
for (int runeID : _runeSetMap.get(npc.runeSetID)) { for (int runeID : _runeSetMap.get(npc.runeSetID)) {
// Shopkeeper is already applied above and most rune sets repeat it
if (runeID == 252620)
continue;
RuneBase rb = RuneBase.getRuneBase(runeID); RuneBase rb = RuneBase.getRuneBase(runeID);
if (rb != null) { if (rb != null) {
CharacterRune toApply = new CharacterRune(rb, npc.getObjectUUID()); CharacterRune toApply = new CharacterRune(rb, npc.getObjectUUID());
@@ -546,14 +536,14 @@ public enum NPCManager {
public static long calcRollingDuration(NPC vendor, int templateID) { public static long calcRollingDuration(NPC vendor, int templateID) {
CObjectTemplate template = CObjectTemplate.lookup(templateID); ItemTemplate template = ItemTemplate.templates.get(templateID);
float rollingDuration; float rollingDuration;
if (template == null) if (template == null)
return 0; return 0;
if (template.getItemBaneRank() > 0) if (template.item_bane_rank > 0)
return (long) (template.getItemBaneRank() * 60 * 60 * 3 * 1000 * Float.parseFloat(ConfigManager.MB_PRODUCTION_RATE.getValue())); return (long) (template.item_bane_rank * 60 * 60 * 3 * 1000 * Float.parseFloat(ConfigManager.MB_PRODUCTION_RATE.getValue()));
if (vendor.building == null) if (vendor.building == null)
return 600; return 600;
+3 -3
View File
@@ -2255,12 +2255,12 @@ public enum PowersManager {
if (pb.targetItem()) if (pb.targetItem())
return true; return true;
// TODO add these checks later // TODO add these checks later
else if (pb.targetArmor() && item.template.getItemType().equals(ItemType.ARMOR)) else if (pb.targetArmor() && item.template.item_type.equals(ItemType.ARMOR))
return true; return true;
else if (pb.targetJewelry() && item.template.getItemType().equals(ItemType.JEWELRY)) else if (pb.targetJewelry() && item.template.item_type.equals(ItemType.JEWELRY))
return true; return true;
else else
return pb.targetWeapon() && item.template.getItemType().equals(ItemType.WEAPON); return pb.targetWeapon() && item.template.item_type.equals(ItemType.WEAPON);
} // How did we get here? all valid targets have been covered } // How did we get here? all valid targets have been covered
else else
return false; return false;
+3 -6
View File
@@ -11,7 +11,7 @@ package engine.jobs;
import engine.job.AbstractScheduleJob; import engine.job.AbstractScheduleJob;
import engine.objects.Bane; import engine.objects.Bane;
import org.joda.time.DateTime; import java.time.LocalDateTime;
public class BaneDefaultTimeJob extends AbstractScheduleJob { public class BaneDefaultTimeJob extends AbstractScheduleJob {
@@ -31,11 +31,8 @@ public class BaneDefaultTimeJob extends AbstractScheduleJob {
return; return;
} }
DateTime defaultTime = new DateTime(this.bane.getPlacementDate()); LocalDateTime defaultTime = this.bane.getPlacementDate()
defaultTime = defaultTime.plusDays(2); .plusDays(2).withHour(22).withMinute(0).withSecond(0).withNano(0);
defaultTime = defaultTime.hourOfDay().setCopy(22);
defaultTime = defaultTime.minuteOfHour().setCopy(0);
defaultTime = defaultTime.secondOfMinute().setCopy(0);
this.bane.setLiveDate(defaultTime); this.bane.setLiveDate(defaultTime);
} }
+4 -4
View File
@@ -12,9 +12,9 @@ import engine.gameManager.DbManager;
import engine.gameManager.ForgeManager; import engine.gameManager.ForgeManager;
import engine.mbEnums; import engine.mbEnums;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.ItemTemplate;
import engine.objects.NPC; import engine.objects.NPC;
import engine.objects.Warehouse; import engine.objects.Warehouse;
import engine.parsers.objects.CObjectTemplate;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
@@ -127,16 +127,16 @@ public class WorkOrder implements Delayed {
int validation_result = 0; int validation_result = 0;
CObjectTemplate template = CObjectTemplate.lookup(workOrder.templateID); ItemTemplate template = ItemTemplate.templates.get(workOrder.templateID);
if (workOrder.vendor.getBuilding() == null) if (workOrder.vendor.getBuilding() == null)
return 58; //58: The formula is beyond the means of this facility return 58; //58: The formula is beyond the means of this facility
if (!workOrder.vendor.charItemManager.hasRoomInventory(template.getItemWt())) if (!workOrder.vendor.charItemManager.hasRoomInventory(template.item_wt))
return 30; //30: That person cannot carry that item return 30; //30: That person cannot carry that item
if ((workOrder.prefixToken != 0 || workOrder.suffixToken != 0) && if ((workOrder.prefixToken != 0 || workOrder.suffixToken != 0) &&
!workOrder.vendor.getItemModTable().contains(ForgeManager.getVendorModTable(workOrder.templateID))) !workOrder.vendor.getItemModTable().contains((template.modTable)))
return 59; //59: This hireling does not have this formula return 59; //59: This hireling does not have this formula
if (!Warehouse.calcCostOverrun(workOrder).isEmpty()) if (!Warehouse.calcCostOverrun(workOrder).isEmpty())
+30
View File
@@ -583,6 +583,36 @@ final public class FastMath {
return ret.normalize(); return ret.normalize();
} }
/**
* Turns a String into an Integer hash that the client will recognize.
*
* @param s The String to hash
* @return the Integer hash
*/
public static int hash(String s) {
int out = 0, pad = 0;
for (char c : s.toCharArray()) {
if (c == ' ' || c == '\\') {
pad += 5;
continue;
}
if (c > 0x40 && c < 0x60)
out ^= _rotl((byte) 0x60, pad);
out ^= _rotl((byte) (c & 0xDF), pad);
pad += 5;
}
return out;
}
/**
* Utility function for making hashes
*/
private static int _rotl(int value, int shift) {
if ((shift &= 31) == 0)
return value;
return (value << shift) | (value >> (32 - shift));
}
/** /**
* Gets number of seconds until next hours * Gets number of seconds until next hours
*/ */
+23 -30
View File
@@ -15,6 +15,7 @@ import engine.math.Vector2f;
import engine.math.Vector3f; import engine.math.Vector3f;
import engine.math.Vector3fImmutable; import engine.math.Vector3fImmutable;
import engine.objects.AbstractCharacter; import engine.objects.AbstractCharacter;
import engine.objects.ItemTemplate;
import engine.objects.Shrine; import engine.objects.Shrine;
import engine.objects.Zone; import engine.objects.Zone;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
@@ -823,7 +824,6 @@ public class mbEnums {
ACID, ACID,
DISEASE, DISEASE,
UNKNOWN, UNKNOWN,
ANTISIEGE,
// these added for immunities // these added for immunities
ATTACK, ATTACK,
POWERS, POWERS,
@@ -842,26 +842,34 @@ public class mbEnums {
public static DamageType getDamageType(String modName) { public static DamageType getDamageType(String modName) {
String name;
if (modName.isEmpty()) if (modName.isEmpty())
return DamageType.NONE; return DamageType.NONE;
// Client and DB strings vary in case and punctuation ("Fire", "Anti-Siege") if(modName.toLowerCase().equals("blind"))
modName = "BLINDNESS";
name = modName.replaceAll("[\\s,-]", "").toUpperCase(); if(modName.toLowerCase().equals("powerblock"))
modName = "POWERINHIBITOR";
if (name.equals("BLIND")) //validity check for not looking up damage type that doesn't exist
name = "BLINDNESS"; boolean valid = false;
for(DamageType type : DamageType.values()){
if(type.name().equals(modName))
valid = true;
}
if (name.equals("POWERBLOCK")) if(!valid)
name = "POWERINHIBITOR"; return DamageType.NONE;
for (DamageType type : DamageType.values()) DamageType damageType;
if (type.name().equals(name))
return type;
return DamageType.NONE; try {
damageType = DamageType.valueOf(modName.replace(",", "").toUpperCase());
} catch (Exception e) {
Logger.error(e);
return DamageType.NONE;
}
return damageType;
} }
} }
@@ -1501,15 +1509,6 @@ public class mbEnums {
} }
} }
// rune_type values from the client cache data (COBJECTS/RUNE)
public enum RuneType {
CLASS,
DISCIPLINE,
RACE,
TALENT
}
public enum ShrineType { public enum ShrineType {
Aelfborn(1701900, -75506007, true), Aelfborn(1701900, -75506007, true),
@@ -2762,6 +2761,7 @@ public class mbEnums {
public static HashMap<Integer, ResourceType> templateHashLookup = new HashMap<>(); public static HashMap<Integer, ResourceType> templateHashLookup = new HashMap<>();
public static HashMap<Integer, ResourceType> resourceHashLookup = new HashMap<>(); public static HashMap<Integer, ResourceType> resourceHashLookup = new HashMap<>();
public int templateID; public int templateID;
public ItemTemplate template;
public int resourceHash; public int resourceHash;
public int templateHash; public int templateHash;
public int deposit_limit; public int deposit_limit;
@@ -2769,6 +2769,7 @@ public class mbEnums {
ResourceType(int templateID, int resourceHash, int templateHash, int deposit_limit, int mine_production) { ResourceType(int templateID, int resourceHash, int templateHash, int deposit_limit, int mine_production) {
this.templateID = templateID; this.templateID = templateID;
this.template = ItemTemplate.templates.get(this.templateID);
this.resourceHash = resourceHash; this.resourceHash = resourceHash;
this.templateHash = templateHash; this.templateHash = templateHash;
this.deposit_limit = deposit_limit; this.deposit_limit = deposit_limit;
@@ -2907,14 +2908,6 @@ public class mbEnums {
EMPTY_NEWITEM; EMPTY_NEWITEM;
} }
// Cache JSON names. UNKNOWN is raw 0, which the client treats as no slot (sb.exe 0x4AC810).
public enum SheathSlot {
UNKNOWN,
BACK,
WAIST,
NONE
}
public enum AttributeType { public enum AttributeType {
None, None,
Strength, Strength,
+56 -50
View File
@@ -14,10 +14,12 @@ import engine.gameManager.*;
import engine.math.Vector3f; import engine.math.Vector3f;
import engine.math.Vector3fImmutable; import engine.math.Vector3fImmutable;
import engine.mbEnums; import engine.mbEnums;
import engine.mbEnums.DispatchChannel;
import engine.mobileAI.Threads.MobAIThread; import engine.mobileAI.Threads.MobAIThread;
import engine.mobileAI.Threads.ReSpawner; import engine.mobileAI.Threads.ReSpawner;
import engine.mobileAI.utilities.MovementUtilities; import engine.mobileAI.utilities.MovementUtilities;
import engine.net.client.msg.PerformActionMsg; import engine.net.client.msg.PerformActionMsg;
import engine.net.client.msg.PowerProjectileMsg;
import engine.objects.*; import engine.objects.*;
import engine.powers.ActionsBase; import engine.powers.ActionsBase;
import engine.powers.PowersBase; import engine.powers.PowersBase;
@@ -44,11 +46,6 @@ public class MobAI {
// //
// CombatManager.class implements shared combat routines for all avatars. // CombatManager.class implements shared combat routines for all avatars.
// Pet aggro scan in checkForAggro stays off until it checks rune enemy lists,
// filters its targets and keeps pet targets (MBDATA/docs/plan-mask-pet.md steps 2-4).
private static final boolean PET_AGGRO_ENABLED = false;
private static void attackTarget(Mob mob, AbstractWorldObject target) { private static void attackTarget(Mob mob, AbstractWorldObject target) {
try { try {
@@ -96,7 +93,7 @@ public class MobAI {
mob.updateLocation(); mob.updateLocation();
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage());
} }
} }
@@ -115,9 +112,7 @@ public class MobAI {
if (mob.behaviourType.callsForHelp) if (mob.behaviourType.callsForHelp)
mobCallForHelp(mob); mobCallForHelp(mob);
// siege engines drop targets on their own attack range in determineAction if (!MovementUtilities.inRangeDropAggro(mob, target)) {
if (!mob.isSiege() && !MovementUtilities.inRangeDropAggro(mob, target)) {
mob.setCombatTarget(null); mob.setCombatTarget(null);
return; return;
} }
@@ -138,7 +133,7 @@ public class MobAI {
target.getPet().setCombatTarget(mob); target.getPet().setCombatTarget(mob);
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackPlayer"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackPlayer" + " " + e.getMessage());
} }
} }
@@ -160,10 +155,20 @@ public class MobAI {
if (guard.getCombatTarget() == null && !guard.getGuild().equals(mob.getGuild())) if (guard.getCombatTarget() == null && !guard.getGuild().equals(mob.getGuild()))
guard.setCombatTarget(mob); guard.setCombatTarget(mob);
if (mob.isSiege())
MovementManager.sendRWSSMsg(mob);
CombatManager.combatCycle(mob, target); CombatManager.combatCycle(mob, target);
if (mob.isSiege()) {
PowerProjectileMsg ppm = new PowerProjectileMsg(mob, target);
ppm.setRange(50);
DispatchManager.dispatchMsgToInterestArea(mob, ppm, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
}
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackBuilding"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackBuilding" + " " + e.getMessage());
} }
} }
@@ -181,7 +186,7 @@ public class MobAI {
CombatManager.combatCycle(mob, target); CombatManager.combatCycle(mob, target);
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackMob"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackMob" + " " + e.getMessage());
} }
} }
@@ -243,7 +248,7 @@ public class MobAI {
MovementUtilities.aiMove(mob, mob.destination, true); MovementUtilities.aiMove(mob, mob.destination, true);
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: Patrol"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage());
} }
} }
@@ -285,7 +290,7 @@ public class MobAI {
return mob.nextCastTime <= System.currentTimeMillis(); return mob.nextCastTime <= System.currentTimeMillis();
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: canCast"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: canCast" + " " + e.getMessage());
} }
return false; return false;
} }
@@ -382,7 +387,7 @@ public class MobAI {
return true; return true;
} }
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCast"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCast" + " " + e.getMessage());
} }
return false; return false;
} }
@@ -447,7 +452,7 @@ public class MobAI {
mob.nextCallForHelp = System.currentTimeMillis() + 60000; mob.nextCallForHelp = System.currentTimeMillis() + 60000;
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCallForHelp"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCallForHelp" + " " + e.getMessage());
} }
} }
@@ -513,16 +518,7 @@ public class MobAI {
boolean bypassLoadedPlayerCheck = false; boolean bypassLoadedPlayerCheck = false;
if (mob.isPlayerGuard() || mob.isSiege()) { if (mob.isPlayerGuard() || mob.isSiege()) {
bypassLoadedPlayerCheck = true; bypassLoadedPlayerCheck = true;
if (mob.combatTarget != null && mob.combatTarget.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter))
if (mob.isSiege()) {
// siege engines hold a character target until it dies or leaves their attack range
if (mob.combatTarget != null && AbstractCharacter.IsAbstractCharacter(mob.combatTarget))
if (mob.combatTarget.loc.distanceSquared(mob.loc) > mob.getRange() * mob.getRange())
mob.setCombatTarget(null);
} else if (mob.combatTarget != null && mob.combatTarget.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter))
if (mob.combatTarget.loc.distanceSquared(mob.loc) > 10000) if (mob.combatTarget.loc.distanceSquared(mob.loc) > 10000)
mob.setCombatTarget(null); mob.setCombatTarget(null);
} }
@@ -548,7 +544,7 @@ public class MobAI {
PlayerCharacter target = (PlayerCharacter) mob.getCombatTarget(); PlayerCharacter target = (PlayerCharacter) mob.getCombatTarget();
if (!mob.isSiege() && !mob.playerAgroMap.containsKey(target.getObjectUUID())) { if (!mob.playerAgroMap.containsKey(target.getObjectUUID())) {
mob.setCombatTarget(null); mob.setCombatTarget(null);
return; return;
} }
@@ -579,7 +575,7 @@ public class MobAI {
break; break;
} }
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: DetermineAction"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: DetermineAction" + " " + e.getMessage());
} }
} }
@@ -634,7 +630,7 @@ public class MobAI {
} }
} }
if (PET_AGGRO_ENABLED && aiAgent.getCombatTarget() == null) { if (aiAgent.getCombatTarget() == null) {
//look for pets to aggro if no players found to aggro //look for pets to aggro if no players found to aggro
@@ -653,7 +649,7 @@ public class MobAI {
} }
} }
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForAggro"); Logger.info(aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForAggro" + " " + e.getMessage());
} }
} }
@@ -706,7 +702,7 @@ public class MobAI {
} }
} }
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckMobMovement"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckMobMovement" + " " + e.getMessage());
} }
} }
@@ -750,7 +746,7 @@ public class MobAI {
ReSpawner.respawnQueue.put(aiAgent); ReSpawner.respawnQueue.put(aiAgent);
} }
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForRespawn"); Logger.info(aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForRespawn" + " " + e.getMessage());
} }
} }
@@ -765,7 +761,7 @@ public class MobAI {
if (mob.getCombatTarget() == null) if (mob.getCombatTarget() == null)
return; return;
if (mob.getCombatTarget().getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) && !MovementUtilities.inRangeDropAggro(mob, (PlayerCharacter) mob.getCombatTarget()) && !mob.agentType.equals(mbEnums.AIAgentType.PET) && !mob.isSiege()) { if (mob.getCombatTarget().getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) && !MovementUtilities.inRangeDropAggro(mob, (PlayerCharacter) mob.getCombatTarget()) && !mob.agentType.equals(mbEnums.AIAgentType.PET)) {
mob.setCombatTarget(null); mob.setCombatTarget(null);
return; return;
@@ -773,7 +769,7 @@ public class MobAI {
attackTarget(mob, mob.getCombatTarget()); attackTarget(mob, mob.getCombatTarget());
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForAttack"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForAttack" + " " + e.getMessage());
} }
} }
@@ -816,7 +812,7 @@ public class MobAI {
mob.playerAgroMap.replaceAll((e, v) -> 0f); mob.playerAgroMap.replaceAll((e, v) -> 0f);
} }
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckToSendMobHome"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckToSendMobHome" + " " + e.getMessage());
} }
} }
@@ -855,7 +851,7 @@ public class MobAI {
mob.updateMovementState(); mob.updateMovementState();
mob.updateLocation(); mob.updateLocation();
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: chaseTarget"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: chaseTarget" + " " + e.getMessage());
} }
} }
@@ -881,17 +877,13 @@ public class MobAI {
if (aggroMob.agentType.equals(mbEnums.AIAgentType.PET)) if (aggroMob.agentType.equals(mbEnums.AIAgentType.PET))
continue; continue;
//don't attack siege engines
if (aggroMob.isSiege())
continue;
if (mob.getLoc().distanceSquared2D(aggroMob.getLoc()) > sqr(50)) if (mob.getLoc().distanceSquared2D(aggroMob.getLoc()) > sqr(50))
continue; continue;
mob.setCombatTarget(aggroMob); mob.setCombatTarget(aggroMob);
} }
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: SafeGuardAggro"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: SafeGuardAggro" + " " + e.getMessage());
} }
} }
@@ -921,7 +913,7 @@ public class MobAI {
checkForAttack(mob); //only check to attack if combat target is not null checkForAttack(mob); //only check to attack if combat target is not null
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardLogic"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardLogic" + " " + e.getMessage());
} }
} }
@@ -954,7 +946,7 @@ public class MobAI {
mob.setHealth(mob.getHealthMax()); mob.setHealth(mob.getHealthMax());
} }
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: PetLogic"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: PetLogic" + " " + e.getMessage());
} }
} }
@@ -978,7 +970,7 @@ public class MobAI {
} }
checkForAttack(mob); checkForAttack(mob);
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: HamletGuardLogic"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: HamletGuardLogic" + " " + e.getMessage());
} }
} }
@@ -1051,7 +1043,7 @@ public class MobAI {
checkForAttack(mob); checkForAttack(mob);
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: DefaultLogic"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: DefaultLogic" + " " + e.getMessage());
} }
} }
@@ -1107,11 +1099,25 @@ public class MobAI {
return; return;
} }
} }
if (mob.getCombatTarget() == null) {
// guards never auto-aggro siege engines; they only respond when one damages a city building //look for siege equipment to aggro if no players found to aggro
HashSet<AbstractWorldObject> awoList = WorldGrid.getObjectsInRangePartial(mob, MobAIThread.AI_BASE_AGGRO_RANGE, MBServerStatics.MASK_SIEGE);
for (AbstractWorldObject awoMob : awoList) {
Mob aggroMob = (Mob) awoMob;
if (guardCanAggro(mob, aggroMob)) {
mob.setCombatTarget(aggroMob);
return;
}
}
}
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForPlayerGuardAggro"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForPlayerGuardAggro" + e.getMessage());
} }
} }
@@ -1174,7 +1180,7 @@ public class MobAI {
} }
} }
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardCanAggro"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardCanAggro" + " " + e.getMessage());
} }
return false; return false;
} }
@@ -1226,7 +1232,7 @@ public class MobAI {
} }
} }
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: randomGuardPatrolPoints"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: randomGuardPatrolPoints" + " " + e);
} }
} }
@@ -1261,7 +1267,7 @@ public class MobAI {
} }
return mostHatedTarget; return mostHatedTarget;
} catch (Exception e) { } catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: ChangeTargetFromMostHated"); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: ChangeTargetFromMostHated" + " " + e.getMessage());
} }
return null; return null;
} }
+9 -8
View File
@@ -12,7 +12,8 @@ package engine.net;
import engine.math.Vector3f; import engine.math.Vector3f;
import engine.math.Vector3fImmutable; import engine.math.Vector3fImmutable;
import engine.util.ByteBufferUtils; import engine.util.ByteBufferUtils;
import org.joda.time.DateTime; import java.time.Instant;
import java.time.ZoneId;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@@ -57,13 +58,13 @@ public class ByteBufferWriter {
this.bb.putLong(x); this.bb.putLong(x);
} }
public synchronized void putDateTime(DateTime dateTime) { public synchronized void putDateTime(Instant dateTime) {
this.put((byte) dateTime.getDayOfMonth()); this.put((byte) dateTime.atZone(ZoneId.systemDefault()).toLocalDate().getDayOfMonth());
this.put((byte) ((byte) dateTime.getMonthOfYear() - 1)); this.put((byte) ((byte) dateTime.atZone(ZoneId.systemDefault()).toLocalDate().getMonthValue() - 1));
this.putInt(dateTime.getYear() - 1900); this.putInt(dateTime.atZone(ZoneId.systemDefault()).toLocalDate().getYear() - 1900);
this.put((byte) dateTime.getHourOfDay()); this.put((byte) dateTime.atZone(ZoneId.systemDefault()).toLocalTime().getHour());
this.put((byte) dateTime.getMinuteOfHour()); this.put((byte) dateTime.atZone(ZoneId.systemDefault()).toLocalTime().getMinute());
this.put((byte) dateTime.getSecondOfDay()); this.put((byte) dateTime.atZone(ZoneId.systemDefault()).toLocalTime().getSecond());
} }
public synchronized void putLocalDateTime(LocalDateTime dateTime) { public synchronized void putLocalDateTime(LocalDateTime dateTime) {
+2 -2
View File
@@ -14,7 +14,7 @@ import engine.gameManager.ChatManager;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import java.time.Instant;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@@ -85,7 +85,7 @@ public class NetMsgFactory {
if (protocolMsg == Protocol.NONE) { if (protocolMsg == Protocol.NONE) {
String errorString = DateTime.now().toString() + origin.lastProtocol.name(); String errorString = Instant.now().toString() + origin.lastProtocol.name();
int errorCode = errorString.hashCode(); int errorCode = errorString.hashCode();
@@ -22,7 +22,7 @@ import engine.net.client.msg.guild.GuildInfoMsg;
import engine.objects.Guild; import engine.objects.Guild;
import engine.objects.GuildHistory; import engine.objects.GuildHistory;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import org.joda.time.DateTime; import java.time.Instant;
public class AcceptInviteToGuildHandler extends AbstractClientMsgHandler { public class AcceptInviteToGuildHandler extends AbstractClientMsgHandler {
@@ -90,8 +90,8 @@ public class AcceptInviteToGuildHandler extends AbstractClientMsgHandler {
//Add to guild History //Add to guild History
if (player.getGuild() != null) { if (player.getGuild() != null) {
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(player.getGuildUUID(), player, DateTime.now(), GuildHistoryType.JOIN)) { if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(player.getGuildUUID(), player, Instant.now(), GuildHistoryType.JOIN)) {
GuildHistory guildHistory = new GuildHistory(player.getGuildUUID(), player.getGuild().getName(), DateTime.now(), GuildHistoryType.JOIN); GuildHistory guildHistory = new GuildHistory(player.getGuildUUID(), player.getGuild().getName(), Instant.now(), GuildHistoryType.JOIN);
player.getGuildHistory().add(guildHistory); player.getGuildHistory().add(guildHistory);
} }
} }
@@ -46,7 +46,7 @@ public class ActivateNPCMsgHandler extends AbstractClientMsgHandler {
// Filter hirelings by slot type // Filter hirelings by slot type
for (Item hirelings : player.getInventory()) { for (Item hirelings : player.getInventory()) {
if (hirelings.template.getItemType().equals(ItemType.EMPLOYMENTCONTRACT)) { if (hirelings.template.item_type.equals(ItemType.EMPLOYMENTCONTRACT)) {
contract = DbManager.ContractQueries.GET_CONTRACT(hirelings.templateID); contract = DbManager.ContractQueries.GET_CONTRACT(hirelings.templateID);
@@ -78,7 +78,7 @@ public class AddItemToTradeWindowMsgHandler extends AbstractClientMsgHandler {
if (!item.validForInventory(source.getClientConnection(), source, source.charItemManager)) if (!item.validForInventory(source.getClientConnection(), source, source.charItemManager))
return false; return false;
if (!tradingWith.hasRoomTrade(item.template.getItemWt())) { if (!tradingWith.hasRoomTrade(item.template.item_wt)) {
dispatch = Dispatch.borrow(source, msg); dispatch = Dispatch.borrow(source, msg);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.PRIMARY); DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.PRIMARY);
return false; return false;
@@ -25,7 +25,7 @@ import engine.objects.Guild;
import engine.objects.GuildHistory; import engine.objects.GuildHistory;
import engine.objects.GuildStatusController; import engine.objects.GuildStatusController;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import org.joda.time.DateTime; import java.time.Instant;
public class BanishUnbanishHandler extends AbstractClientMsgHandler { public class BanishUnbanishHandler extends AbstractClientMsgHandler {
@@ -95,8 +95,8 @@ public class BanishUnbanishHandler extends AbstractClientMsgHandler {
//Set guild history //Set guild history
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(guild.getObjectUUID(), toBanish, DateTime.now(), GuildHistoryType.BANISHED)) { if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(guild.getObjectUUID(), toBanish, Instant.now(), GuildHistoryType.BANISHED)) {
GuildHistory guildHistory = new GuildHistory(toBanish.getGuildUUID(), toBanish.getGuild().getName(), DateTime.now(), GuildHistoryType.BANISHED); GuildHistory guildHistory = new GuildHistory(toBanish.getGuildUUID(), toBanish.getGuild().getName(), Instant.now(), GuildHistoryType.BANISHED);
toBanish.getGuildHistory().add(guildHistory); toBanish.getGuildHistory().add(guildHistory);
} }
} }
@@ -97,13 +97,9 @@ public class DestroyBuildingHandler extends AbstractClientMsgHandler {
if (city == null) if (city == null)
return true; return true;
Warehouse.destroyedWarehouses.remove(building.getObjectUUID()); DbManager.WarehouseQueries.DELETE_WAREHOUSE(city.warehouse);
// Rubble no longer owns city.warehouse, which may be null or a newly placed warehouse city.warehouse = null;
if (city.warehouse != null && building.getRank() != -1) {
DbManager.WarehouseQueries.DELETE_WAREHOUSE(city.warehouse);
city.warehouse = null;
}
} }
@@ -24,7 +24,6 @@ import engine.net.client.msg.guild.GuildInfoMsg;
import engine.objects.Guild; import engine.objects.Guild;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.parsers.objects.DeedTemplate;
import engine.util.StringUtils; import engine.util.StringUtils;
public class GuildCreationFinalizeHandler extends AbstractClientMsgHandler { public class GuildCreationFinalizeHandler extends AbstractClientMsgHandler {
@@ -43,7 +42,6 @@ public class GuildCreationFinalizeHandler extends AbstractClientMsgHandler {
Guild playerGuild; Guild playerGuild;
Item charter; Item charter;
DeedTemplate charterDeed;
Dispatch dispatch; Dispatch dispatch;
msg = (GuildCreationFinalizeMsg) baseMsg; msg = (GuildCreationFinalizeMsg) baseMsg;
@@ -67,9 +65,7 @@ public class GuildCreationFinalizeHandler extends AbstractClientMsgHandler {
// Item must be a valid charterType (type 10 in db) // Item must be a valid charterType (type 10 in db)
charterDeed = DeedTemplate._deeds.get(charter.templateID); if (charter == null || (charter.template.item_type.equals(ItemType.CHARTER) == false)) {
if (charterDeed == null || (charterDeed.item_type.equals(ItemType.CHARTER) == false)) {
ErrorPopupMsg.sendErrorPopup(player, GuildManager.NO_CHARTER_FOUND); ErrorPopupMsg.sendErrorPopup(player, GuildManager.NO_CHARTER_FOUND);
return true; return true;
} }
@@ -238,10 +238,10 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
if (targetItem == null) if (targetItem == null)
return; return;
if (targetItem.template.getItemType().equals(ItemType.GOLD)) if (targetItem.template.item_type.equals(ItemType.GOLD))
return; return;
if (!vendor.charItemManager.hasRoomInventory(targetItem.template.getItemWt())) { if (!vendor.charItemManager.hasRoomInventory(targetItem.template.item_wt)) {
ErrorPopupMsg.sendErrorPopup(player, 21); ErrorPopupMsg.sendErrorPopup(player, 21);
return; return;
} }
@@ -319,7 +319,7 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
if (targetItem == null) if (targetItem == null)
continue; continue;
if (targetItem.template.getItemType().equals(ItemType.GOLD)) if (targetItem.template.item_type.equals(ItemType.GOLD))
return; return;
if (!vendor.charItemManager.doesCharOwnThisItem(targetItem.getObjectUUID())) if (!vendor.charItemManager.doesCharOwnThisItem(targetItem.getObjectUUID()))
@@ -328,14 +328,14 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
if (!vendor.charItemManager.inventoryContains(targetItem)) if (!vendor.charItemManager.inventoryContains(targetItem))
continue; continue;
itemValue = targetItem.template.getItemValue(); itemValue = targetItem.template.item_value;
if (vendor.getBuilding().getStrongboxValue() + itemValue > vendor.getBuilding().getMaxGold()) { if (vendor.getBuilding().getStrongboxValue() + itemValue > vendor.getBuilding().getMaxGold()) {
ErrorPopupMsg.sendErrorPopup(player, 201); ErrorPopupMsg.sendErrorPopup(player, 201);
break; break;
} }
switch (targetItem.template.getItemType()) { switch (targetItem.template.item_type) {
case EMPLOYMENTCONTRACT: case EMPLOYMENTCONTRACT:
case CHARTER: case CHARTER:
case DEED: case DEED:
@@ -465,13 +465,13 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
if (targetItem == null) if (targetItem == null)
return; return;
if (targetItem.template.getItemType().equals(ItemType.GOLD)) if (targetItem.template.item_type.equals(ItemType.GOLD))
return; return;
if (!vendor.charItemManager.inventoryContains(targetItem)) if (!vendor.charItemManager.inventoryContains(targetItem))
return; return;
if (!player.charItemManager.hasRoomInventory(targetItem.template.getItemWt())) if (!player.charItemManager.hasRoomInventory(targetItem.template.item_wt))
return; return;
player.charItemManager.buyFromNPC(targetItem, vendor); player.charItemManager.buyFromNPC(targetItem, vendor);
@@ -161,7 +161,7 @@ public class LootMsgHandler extends AbstractClientMsgHandler {
if (itemRet == null) if (itemRet == null)
return true; return true;
if (item.template.getItemType().equals(mbEnums.ItemType.GOLD)) { if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) {
// this is done to prevent the temporary goldItem item // this is done to prevent the temporary goldItem item
// (from the mob) from appearing in player's inventory. // (from the mob) from appearing in player's inventory.
// It also updates the goldItem quantity display // It also updates the goldItem quantity display
@@ -187,7 +187,7 @@ public class LootMsgHandler extends AbstractClientMsgHandler {
//TODO send group loot message if player is grouped and visible //TODO send group loot message if player is grouped and visible
Group group = GroupManager.getGroup(player); Group group = GroupManager.getGroup(player);
if (group != null && group.getSplitGold() && (item.template.getItemType().equals(mbEnums.ItemType.GOLD) == false)) { if (group != null && group.getSplitGold() && (item.template.item_type.equals(mbEnums.ItemType.GOLD) == false)) {
String name = item.getName(); String name = item.getName();
String text = player.getFirstName() + " has looted " + name + '.'; String text = player.getFirstName() + " has looted " + name + '.';
ChatManager.chatGroupInfoCanSee(player, text); ChatManager.chatGroupInfoCanSee(player, text);
@@ -202,7 +202,7 @@ public class LootMsgHandler extends AbstractClientMsgHandler {
if (itemRet == null) if (itemRet == null)
return true; return true;
if (item.template.getItemType().equals(mbEnums.ItemType.GOLD)) { if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) {
// this is done to prevent the temporary goldItem item // this is done to prevent the temporary goldItem item
// (from the mob) from appearing in player's inventory. // (from the mob) from appearing in player's inventory.
// It also updates the goldItem quantity display // It also updates the goldItem quantity display
@@ -241,7 +241,7 @@ public class LootMsgHandler extends AbstractClientMsgHandler {
//TODO send group loot message if player is grouped and visible //TODO send group loot message if player is grouped and visible
Group group = GroupManager.getGroup(player); Group group = GroupManager.getGroup(player);
if (group != null && group.getSplitGold() && (item.template.getItemType().equals(mbEnums.ItemType.GOLD) == false)) { if (group != null && group.getSplitGold() && (item.template.item_type.equals(mbEnums.ItemType.GOLD) == false)) {
String name = item.getName(); String name = item.getName();
String text = player.getFirstName() + " has looted " + name + '.'; String text = player.getFirstName() + " has looted " + name + '.';
ChatManager.chatGroupInfoCanSee(player, text); ChatManager.chatGroupInfoCanSee(player, text);
@@ -15,7 +15,7 @@ import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.ManageCityAssetsMsg; import engine.net.client.msg.ManageCityAssetsMsg;
import engine.net.client.msg.PlaceAssetMsg; import engine.net.client.msg.PlaceAssetMsg;
import engine.objects.*; import engine.objects.*;
import org.joda.time.DateTime; import java.time.LocalDateTime;
/* /*
* @Author: * @Author:
@@ -141,9 +141,17 @@ public class ManageCityAssetMsgHandler extends AbstractClientMsgHandler {
return true; return true;
} }
Warehouse warehouse = Warehouse.destroyedWarehouses.get(building.getObjectUUID()); City city = building.getCity();
if (warehouse == null || Warehouse.isEmpty(warehouse)) { if (city == null)
return true;
Warehouse warehouse = city.warehouse;
if (warehouse == null)
return true;
if (Warehouse.isEmpty(warehouse)) {
ErrorPopupMsg.sendErrorPopup(player, 167); // no more resources. ErrorPopupMsg.sendErrorPopup(player, 167); // no more resources.
return true; return true;
} }
@@ -243,11 +251,10 @@ public class ManageCityAssetMsgHandler extends AbstractClientMsgHandler {
return true; return true;
} }
DateTime baneLive = new DateTime(bane.getPlacementDate()); LocalDateTime baneLive = bane.getPlacementDate();
baneLive = baneHour == 24 ? baneLive.plusDays(3) : baneLive.plusDays(2); baneLive = baneHour == 24 ? baneLive.plusDays(3) : baneLive.plusDays(2);
baneLive = baneHour == 24 ? baneLive.hourOfDay().setCopy(0) : baneLive.hourOfDay().setCopy(baneHour); baneLive = baneHour == 24 ? baneLive.withHour(0) : baneLive.withHour(baneHour);
baneLive = baneLive.minuteOfHour().setCopy(0); baneLive = baneLive.withMinute(0).withSecond(1).withNano(0);
baneLive = baneLive.secondOfMinute().setCopy(1);
bane.setLiveDate(baneLive); bane.setLiveDate(baneLive);
outMsg.actionType = 18; outMsg.actionType = 18;
@@ -8,7 +8,6 @@ import engine.net.Dispatch;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.*; import engine.net.client.msg.*;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.DeedTemplate;
import engine.powers.PowersBase; import engine.powers.PowersBase;
import java.util.ArrayList; import java.util.ArrayList;
@@ -79,7 +78,7 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
int uuid = item.templateID; int uuid = item.templateID;
switch (item.template.getItemType()) { switch (item.template.item_type) {
case DEED: //buildings case DEED: //buildings
//Call add building screen here, ib.getUseID() get's building ID //Call add building screen here, ib.getUseID() get's building ID
@@ -100,7 +99,7 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
pam.setX(loc.getX() + 64); //offset grid from tol pam.setX(loc.getX() + 64); //offset grid from tol
pam.setY(loc.getY()); pam.setY(loc.getY());
pam.setZ(loc.getZ() + 64); //offset grid from tol pam.setZ(loc.getZ() + 64); //offset grid from tol
pam.addPlacementInfo(DeedTemplate._deeds.get(item.templateID).deed_structure_id); pam.addPlacementInfo(item.template.deed_structure_id);
dispatch = Dispatch.borrow(player, pam); dispatch = Dispatch.borrow(player, pam);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
@@ -188,14 +187,14 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
if (uuid > 680069 && uuid < 680074) //Handle Charter, Deed, Petition, Warrant here if (uuid > 680069 && uuid < 680074) //Handle Charter, Deed, Petition, Warrant here
break; break;
if (item.template.getItemBaneRank() > 0) { if (item.template.item_bane_rank > 0) {
// Only one banestone at a time // Only one banestone at a time
lock.writeLock().lock(); lock.writeLock().lock();
try { try {
if (Bane.summonBanestone(player, origin, item.template.getItemBaneRank()) == true) if (Bane.summonBanestone(player, origin, item.template.item_bane_rank) == true)
itemMan.consume(item); itemMan.consume(item);
} finally { } finally {
lock.writeLock().unlock(); lock.writeLock().unlock();
@@ -226,7 +225,7 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
// Bypass for waterbuckets // Bypass for waterbuckets
if (item.template.getItemType().equals(mbEnums.ItemType.BUCKET)) { if (item.template.item_type.equals(mbEnums.ItemType.BUCKET)) {
// test for valid target type // test for valid target type
if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter) if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter)
@@ -251,9 +250,10 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
} }
if (waterbucketBypass == false) { if (waterbucketBypass == false) {
engine.parsers.objects.PowerGrant powerGrant = item.template.getItemPowerGrant().get(0); String powerString = item.template.item_power_grant.keySet().iterator().next();
PowersBase powerAction = PowersManager.powersBaseByIDString.get(powerGrant.power_type); PowersBase powerAction = PowersManager.powersBaseByIDString.get(powerString);
PowersManager.applyPower(player, target, Vector3fImmutable.ZERO, powerAction.getToken(), powerGrant.power_value, true); int powerValue = item.template.item_power_grant.get(powerString);
PowersManager.applyPower(player, target, Vector3fImmutable.ZERO, powerAction.getToken(), powerValue, true);
} }
itemMan.consume(item); itemMan.consume(item);
} else //just remove the item at this point } else //just remove the item at this point
@@ -266,8 +266,7 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
case RUNE: case RUNE:
if(ApplyRuneMsg.applyRune(uuid, origin, player)) { if(ApplyRuneMsg.applyRune(uuid, origin, player)) {
itemMan.consume(item); itemMan.consume(item);
} else }
ErrorPopupMsg.sendErrorPopup(player, 161);
break; break;
default: //shouldn't be here, consume item default: //shouldn't be here, consume item
dispatch = Dispatch.borrow(player, msg); dispatch = Dispatch.borrow(player, msg);
@@ -18,9 +18,8 @@ import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.PlaceAssetMsg; import engine.net.client.msg.PlaceAssetMsg;
import engine.net.client.msg.PlaceAssetMsg.PlacementInfo; import engine.net.client.msg.PlaceAssetMsg.PlacementInfo;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.DeedTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import java.time.Instant;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@@ -136,8 +135,6 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
private static boolean validateBuildingPlacement(Zone serverZone, PlaceAssetMsg msg, ClientConnection origin, PlayerCharacter player, PlacementInfo placementInfo) { private static boolean validateBuildingPlacement(Zone serverZone, PlaceAssetMsg msg, ClientConnection origin, PlayerCharacter player, PlacementInfo placementInfo) {
Bane bane;
if (serverZone.guild_zone == false) { if (serverZone.guild_zone == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 52, player.getName()); PlaceAssetMsg.sendPlaceAssetError(origin, 52, player.getName());
return false; return false;
@@ -208,15 +205,6 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
return false; return false;
} }
// Siege equipment has its own validation and never reaches here
bane = city.getBane();
if (bane != null) {
PlaceAssetMsg.sendPlaceAssetError(origin, 74, ""); //"Only buildings of war may be placed during a bane"
return false;
}
if (placementCollisionCheck(serverZone, origin, placementInfo)) { if (placementCollisionCheck(serverZone, origin, placementInfo)) {
PlaceAssetMsg.sendPlaceAssetError(origin, 3, ""); // Conflict between proposed assets PlaceAssetMsg.sendPlaceAssetError(origin, 3, ""); // Conflict between proposed assets
return false; return false;
@@ -357,8 +345,8 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
Item contract = null; Item contract = null;
for (Item inventoryItem : playerCharacter.getInventory()) { for (Item inventoryItem : playerCharacter.getInventory()) {
if (inventoryItem.template.getItemType().equals(ItemType.DEED) && if (inventoryItem.template.item_type.equals(ItemType.DEED) &&
DeedTemplate._deeds.get(inventoryItem.templateID).deed_structure_id == buildingList.getBlueprintUUID()) { inventoryItem.template.deed_structure_id == buildingList.getBlueprintUUID()) {
contract = inventoryItem; contract = inventoryItem;
break; break;
} }
@@ -1154,7 +1142,7 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
Blueprint blueprint; Blueprint blueprint;
Building newMesh; Building newMesh;
DateTime completionDate; Instant completionDate;
float vendorRotation; float vendorRotation;
float buildingRotation; float buildingRotation;
@@ -1169,9 +1157,9 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
if ((blueprint.getBuildingGroup().equals(BuildingGroup.SIEGETENT)) if ((blueprint.getBuildingGroup().equals(BuildingGroup.SIEGETENT))
|| (blueprint.getBuildingGroup().equals(BuildingGroup.BULWARK))) || (blueprint.getBuildingGroup().equals(BuildingGroup.BULWARK)))
completionDate = DateTime.now().plusMinutes(15); completionDate = Instant.now().plusSeconds(15 * 60);
else else
completionDate = DateTime.now().plusHours(blueprint.getRankTime(1)); completionDate = Instant.now().plusSeconds(blueprint.getRankTime(1) * 3600);
Vector3fImmutable localLoc = new Vector3fImmutable(ZoneManager.worldToLocal(buildingInfo.getLoc(), currentZone)); Vector3fImmutable localLoc = new Vector3fImmutable(ZoneManager.worldToLocal(buildingInfo.getLoc(), currentZone));
@@ -1240,7 +1228,7 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
ArrayList<AbstractGameObject> shrineObjects = DbManager.ShrineQueries.CREATE_SHRINE( ArrayList<AbstractGameObject> shrineObjects = DbManager.ShrineQueries.CREATE_SHRINE(
currentZone.getObjectUUID(), player.getObjectUUID(), blueprint.getName(), blueprint.getMeshForRank(0), currentZone.getObjectUUID(), player.getObjectUUID(), blueprint.getName(), blueprint.getMeshForRank(0),
localLoc, 1.0f, blueprint.getMaxHealth(0), ProtectionState.PROTECTED, 0, 0, localLoc, 1.0f, blueprint.getMaxHealth(0), ProtectionState.PROTECTED, 0, 0,
DateTime.now().plusHours(blueprint.getRankTime(1)), blueprint.getMeshForRank(0), vendorRotation, buildingRotation, shrineType.name()); Instant.now().plusSeconds(blueprint.getRankTime(1) * 3600), blueprint.getMeshForRank(0), vendorRotation, buildingRotation, shrineType.name());
if (shrineObjects == null) { if (shrineObjects == null) {
PlaceAssetMsg.sendPlaceAssetError(player.getClientConnection(), 1, "A Serious error has occurred. Please post details for to ensure transaction integrity"); PlaceAssetMsg.sendPlaceAssetError(player.getClientConnection(), 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
@@ -1300,7 +1288,7 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
float buildingRotation = buildingInfo.getRot().y; float buildingRotation = buildingInfo.getRot().y;
float vendorRotation = buildingInfo.getW(); float vendorRotation = buildingInfo.getW();
DateTime completionDate = DateTime.now().plusHours(blueprint.getRankTime(1)); Instant completionDate = Instant.now().plusSeconds(blueprint.getRankTime(1) * 3600);
newMesh = DbManager.BuildingQueries.CREATE_BUILDING( newMesh = DbManager.BuildingQueries.CREATE_BUILDING(
@@ -1345,7 +1333,7 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
warehouseBuilding = DbManager.BuildingQueries.CREATE_BUILDING( warehouseBuilding = DbManager.BuildingQueries.CREATE_BUILDING(
currentZone.getObjectUUID(), player.getObjectUUID(), blueprint.getName(), blueprint.getMeshForRank(0), currentZone.getObjectUUID(), player.getObjectUUID(), blueprint.getName(), blueprint.getMeshForRank(0),
localLoc, 1.0f, blueprint.getMaxHealth(0), ProtectionState.NONE, 0, 0, localLoc, 1.0f, blueprint.getMaxHealth(0), ProtectionState.NONE, 0, 0,
DateTime.now().plusHours(blueprint.getRankTime(1)), blueprint.getMeshForRank(0), vendorRotation, buildingRotation); Instant.now().plusSeconds(blueprint.getRankTime(1) * 3600), blueprint.getMeshForRank(0), vendorRotation, buildingRotation);
if (warehouseBuilding == null) { if (warehouseBuilding == null) {
PlaceAssetMsg.sendPlaceAssetError(player.getClientConnection(), 1, "A Serious error has occurred. Please post details for to ensure transaction integrity"); PlaceAssetMsg.sendPlaceAssetError(player.getClientConnection(), 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
@@ -1353,7 +1341,6 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
} }
Warehouse warehouse = new Warehouse(warehouseBuilding); Warehouse warehouse = new Warehouse(warehouseBuilding);
Warehouse.destroyedWarehouses.values().removeIf(destroyed -> destroyed.city == city);
city.warehouse = warehouse; city.warehouse = warehouse;
DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse); DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse);
@@ -85,7 +85,7 @@ public class RepairMsgHandler extends AbstractClientMsgHandler {
//make sure item is damaged and not destroyed //make sure item is damaged and not destroyed
short dur = (short) toRepair.combat_health_current; short dur = (short) toRepair.combat_health_current;
short max = (short) toRepair.template.getCombatHealthFull(); short max = (short) toRepair.template.combat_health_full;
//account for durability modifications //account for durability modifications
@@ -68,7 +68,7 @@ public class TransferItemFromBankMsgHandler extends AbstractClientMsgHandler {
return true; return true;
; ;
if (item.template.getItemType().equals(mbEnums.ItemType.GOLD)) { if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) {
if (!itemManager.moveGoldToInventory(item, msg.getNumItems())) if (!itemManager.moveGoldToInventory(item, msg.getNumItems()))
return true; return true;
@@ -85,7 +85,7 @@ public class TransferItemFromBankMsgHandler extends AbstractClientMsgHandler {
// Not gold, process update here // Not gold, process update here
if (!itemManager.hasRoomInventory(item.template.getItemWt())) if (!itemManager.hasRoomInventory(item.template.item_wt))
return true; return true;
if (itemManager.moveItemToInventory(item) == false) if (itemManager.moveItemToInventory(item) == false)
@@ -65,7 +65,7 @@ public class TransferItemToBankMsgHandler extends AbstractClientMsgHandler {
return true; return true;
if (item.containerType == mbEnums.ItemContainerType.INVENTORY && itemManager.isBankOpen()) if (item.containerType == mbEnums.ItemContainerType.INVENTORY && itemManager.isBankOpen())
if (item.template.getItemType().equals(mbEnums.ItemType.GOLD)) { if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) {
if (!itemManager.moveGoldToBank(item, msg.getNumItems())) if (!itemManager.moveGoldToBank(item, msg.getNumItems()))
return true; return true;
UpdateGoldMsg goldMes = new UpdateGoldMsg(player); UpdateGoldMsg goldMes = new UpdateGoldMsg(player);
@@ -76,7 +76,7 @@ public class TransferItemToBankMsgHandler extends AbstractClientMsgHandler {
} else { } else {
if (!itemManager.hasRoomBank(item.template.getItemWt())) if (!itemManager.hasRoomBank(item.template.item_wt))
return true; return true;
if (!itemManager.moveItemToBank(item)) if (!itemManager.moveItemToBank(item))
@@ -86,7 +86,7 @@ public class VendorBuyMsgHandler extends AbstractClientMsgHandler {
if (me.objectUUID == vendorBuyMsg.getItemID()) { if (me.objectUUID == vendorBuyMsg.getItemID()) {
//test room available for item //test room available for item
if (!itemMan.hasRoomInventory(me.template.getItemWt())) if (!itemMan.hasRoomInventory(me.template.item_wt))
return true; return true;
int cost = me.getValue(); int cost = me.getValue();
@@ -148,10 +148,10 @@ public class VendorBuyMsgHandler extends AbstractClientMsgHandler {
//test room available for item //test room available for item
if (!itemMan.hasRoomInventory(vendorItem.template.getItemWt())) if (!itemMan.hasRoomInventory(vendorItem.template.item_wt))
return true; return true;
int cost = vendorItem.template.getItemValue(); int cost = vendorItem.template.item_value;
if (vendorItem.flags.contains(mbEnums.ItemFlags.Identified) || vendorItem.isCustomValue()) if (vendorItem.flags.contains(mbEnums.ItemFlags.Identified) || vendorItem.isCustomValue())
cost = vendorItem.magicValue; cost = vendorItem.magicValue;
@@ -94,7 +94,7 @@ public class VendorSellMsgHandler extends AbstractClientMsgHandler {
return true; return true;
if (npc.getParentZone() != null && npc.getParentZone().playerCityUUID != 0) if (npc.getParentZone() != null && npc.getParentZone().playerCityUUID != 0)
if (!npc.charItemManager.hasRoomInventory(sell.template.getItemWt())) { if (!npc.charItemManager.hasRoomInventory(sell.template.item_wt)) {
ErrorPopupMsg.sendErrorPopup(player, 21); ErrorPopupMsg.sendErrorPopup(player, 21);
return true; return true;
} }
@@ -104,7 +104,7 @@ public class VendorSellMsgHandler extends AbstractClientMsgHandler {
//get goldItem cost to sell //get goldItem cost to sell
cost = (int) (sell.template.getItemValue() * (sell.combat_health_current / sell.template.getCombatHealthFull())); cost = (int) (sell.template.item_value * (sell.combat_health_current / sell.template.combat_health_full));
float bargain = player.getBargain(); float bargain = player.getBargain();
float profit = npc.getBuyPercent(player) + bargain; float profit = npc.getBuyPercent(player) + bargain;
+72 -73
View File
@@ -22,17 +22,10 @@ import engine.server.MBServerStatics;
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.concurrent.ConcurrentHashMap;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class ApplyRuneMsg extends ClientNetMsg { public class ApplyRuneMsg extends ClientNetMsg {
// Client ArcCharacter_AddRune (0x4695D0)
private static final int MAX_TALENTS = 8;
private int targetType; private int targetType;
private int targetID; private int targetID;
private int removeRuneBase; private int removeRuneBase;
@@ -85,28 +78,67 @@ public class ApplyRuneMsg extends ClientNetMsg {
return false; return false;
} }
//Check race is met
ConcurrentHashMap<Integer, Boolean> races = rb.getRace();
if (races.size() > 0) {
int raceID = playerCharacter.getRaceID();
boolean valid = false;
for (int validID : races.keySet()) {
if (validID == raceID) {
valid = true;
break;
}
}
if (!valid) {
return false;
}
}
//Check base class is met
ConcurrentHashMap<Integer, Boolean> baseClasses = rb.getBaseClass();
if (baseClasses.size() > 0) {
int baseClassID = playerCharacter.getBaseClassID();
boolean valid = false;
for (int validID : baseClasses.keySet()) {
if (validID == baseClassID) {
valid = true;
break;
}
}
if (!valid) {
return false;
}
}
//Check promotion class is met
ConcurrentHashMap<Integer, Boolean> promotionClasses = rb.getPromotionClass();
if (promotionClasses.size() > 0) {
int promotionClassID = playerCharacter.getPromotionClassID();
boolean valid = false;
for (int validID : promotionClasses.keySet()) {
if (validID == promotionClassID) {
valid = true;
break;
}
}
if (!valid) {
return false;
}
}
//Check disciplines are met
ArrayList<CharacterRune> runes = playerCharacter.getRunes(); ArrayList<CharacterRune> runes = playerCharacter.getRunes();
HashSet<Integer> classIDs = new HashSet<>(); ConcurrentHashMap<Integer, Boolean> disciplines = rb.getDiscipline();
HashSet<Integer> heldDiscIDs = new HashSet<>(); if (disciplines.size() > 0) {
for (CharacterRune cr : runes) {
// Client ArcCharacter_MeetsItemReqs (0x475F40) int runeBaseID = cr.getRuneBaseID();
if (!meetsListReq(rb.getRace().keySet(), rb.isRaceRestrict(), Collections.singleton(playerCharacter.getRaceID()))) for (Integer prohID : disciplines.keySet()) {
return false; if (runeBaseID == prohID) {
return false; //Prohibited rune
// A listed base class covers its promotions: base or promotion listed is enough }
classIDs.addAll(rb.getBaseClass().keySet()); }
classIDs.addAll(rb.getPromotionClass().keySet()); }
}
if (!meetsListReq(classIDs, rb.isClassRestrict(), Arrays.asList(playerCharacter.getBaseClassID(), playerCharacter.getPromotionClassID())))
return false;
// Only the new rune's list is checked, not the held discs' lists
for (CharacterRune cr : runes)
if (isDiscipline(cr.getRuneBaseID()))
heldDiscIDs.add(cr.getRuneBaseID());
if (!meetsListReq(rb.getDiscipline().keySet(), rb.isDiscRestrict(), heldDiscIDs))
return false;
int discCount = 0; int discCount = 0;
for (CharacterRune cr : runes) { for (CharacterRune cr : runes) {
@@ -126,32 +158,6 @@ public class ApplyRuneMsg extends ClientNetMsg {
return false; return false;
} }
// Client 0x4768D0 refuses a talent unless its rank beats the held one with the same sub type (rank 0 included);
// AddRune (0x4695D0) then replaces the held talent
CharacterRune replacedRune = null;
if (rb.getRuneType() == mbEnums.RuneType.TALENT) {
int talentCount = 0;
for (CharacterRune cr : runes) {
RuneBase heldRuneBase = cr.getRuneBase();
if (heldRuneBase == null || heldRuneBase.getRuneType() != mbEnums.RuneType.TALENT)
continue;
talentCount++;
if (rb.getSubTypeToken() != 0 && heldRuneBase.getSubTypeToken() == rb.getSubTypeToken())
replacedRune = cr;
}
if (replacedRune != null) {
if (rb.getRank() <= replacedRune.getRuneBase().getRank())
return false;
} else if (talentCount >= MAX_TALENTS)
return false;
}
int strTotal = 0; int strTotal = 0;
int dexTotal = 0; int dexTotal = 0;
int conTotal = 0; int conTotal = 0;
@@ -221,6 +227,11 @@ public class ApplyRuneMsg extends ClientNetMsg {
} }
} }
//Check if max number runes already reached
if (runes.size() > 12) {
return false;
}
//if discipline, check number applied //if discipline, check number applied
if (isDiscipline(runeID)) { if (isDiscipline(runeID)) {
if (playerCharacter.getLevel() < 70) { if (playerCharacter.getLevel() < 70) {
@@ -248,10 +259,13 @@ public class ApplyRuneMsg extends ClientNetMsg {
return false; return false;
} }
//remove the replaced talent from player //remove any overridden runes from player
ArrayList<Integer> overwrite = rb.getOverwrite();
CharacterRune toRemove = null; CharacterRune toRemove = null;
if (replacedRune != null) { if (overwrite.size() > 0) {
toRemove = playerCharacter.removeRune(replacedRune.getRuneBaseID()); for (int overwriteID : overwrite) {
toRemove = playerCharacter.removeRune(overwriteID);
}
} }
//add rune to player //add rune to player
@@ -317,21 +331,6 @@ public class ApplyRuneMsg extends ClientNetMsg {
return runeID > 3000 && runeID < 3050; return runeID > 3000 && runeID < 3050;
} }
// Client ArcItemRestrict_Check (0x4BAC60). An empty list has no requirement; no rune has an empty whitelist.
private static boolean meetsListReq(Set<Integer> listedIDs, boolean restrict, Collection<Integer> heldIDs) {
boolean listed = false;
if (listedIDs.isEmpty())
return true;
for (int heldID : heldIDs)
if (listedIDs.contains(heldID))
listed = true;
return listed != restrict;
}
/** /**
* Serializes the subclass specific items to the supplied NetMsgWriter. * Serializes the subclass specific items to the supplied NetMsgWriter.
*/ */
@@ -17,8 +17,8 @@ import engine.net.Protocol;
import engine.objects.Building; import engine.objects.Building;
import engine.objects.Guild; import engine.objects.Guild;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import java.time.LocalDateTime;
import org.joda.time.Seconds; import java.time.Duration;
public class ArcMineWindowAvailableTimeMsg extends ClientNetMsg { public class ArcMineWindowAvailableTimeMsg extends ClientNetMsg {
@@ -26,8 +26,8 @@ public class ArcMineWindowAvailableTimeMsg extends ClientNetMsg {
private Building treeOfLife; private Building treeOfLife;
private int currentMineHour; private int currentMineHour;
private Seconds secondsLeft; private Duration secondsLeft;
private DateTime lateTime; private LocalDateTime lateTime;
private int late; private int late;
/** /**
@@ -72,15 +72,15 @@ public class ArcMineWindowAvailableTimeMsg extends ClientNetMsg {
currentMineHour = guild.getMineTime(); currentMineHour = guild.getMineTime();
late = MBServerStatics.MINE_LATE_WINDOW; late = MBServerStatics.MINE_LATE_WINDOW;
lateTime = DateTime.now(); lateTime = LocalDateTime.now();
if (late == 0) if (late == 0)
lateTime = lateTime.plusDays(1); lateTime = lateTime.plusDays(1);
lateTime = lateTime.hourOfDay().setCopy(late); lateTime = lateTime.withHour(late);
late = ((late > 23) ? (late - 24) : late); late = ((late > 23) ? (late - 24) : late);
secondsLeft = Seconds.secondsBetween(DateTime.now(), lateTime); secondsLeft = Duration.between(LocalDateTime.now(), lateTime);
} }
/** /**
@@ -106,4 +106,4 @@ public class ArcMineWindowAvailableTimeMsg extends ClientNetMsg {
public void setBuildingUUID(int buildingUUID) { public void setBuildingUUID(int buildingUUID) {
this.buildingUUID = buildingUUID; this.buildingUUID = buildingUUID;
} }
} }
@@ -18,9 +18,6 @@ import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.Protocol; import engine.net.Protocol;
import engine.objects.*; import engine.objects.*;
import org.joda.time.DateTime;
import org.joda.time.Period;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.Set; import java.util.Set;
@@ -397,37 +394,33 @@ public class ManageCityAssetsMsg extends ClientNetMsg {
else else
writer.put((byte) 0); writer.put((byte) 0);
DateTime placedOn = bane.getLiveDate(); LocalDateTime placedOn = bane.getLiveDate();
if (placedOn == null) if (placedOn == null)
placedOn = new DateTime(DateTime.now()); placedOn = LocalDateTime.now();
//set Calander to date of bane live. //set Calander to date of bane live.
DateTime now = DateTime.now(); LocalDateTime now = LocalDateTime.now();
DateTime defaultTime = new DateTime(bane.getPlacementDate()); LocalDateTime defaultTime = bane.getPlacementDate();
DateTime playerEnterWorldTime = new DateTime(this.assetManager.getTimeStamp("EnterWorld")); LocalDateTime playerEnterWorldTime = LocalDateTime.ofInstant(java.time.Instant.ofEpochMilli(this.assetManager.getTimeStamp("EnterWorld")), ZoneId.systemDefault());
Period period = new Period(playerEnterWorldTime.getMillis(), now.getMillis()); int hoursLoggedIn = (int) java.time.Duration.between(playerEnterWorldTime, now).toHours();
int hoursLoggedIn = period.getHours();
hoursLoggedIn = hoursLoggedIn < 0 ? 0 : hoursLoggedIn; hoursLoggedIn = hoursLoggedIn < 0 ? 0 : hoursLoggedIn;
defaultTime = defaultTime.plusDays(2); defaultTime = defaultTime.plusDays(2).withHour(22).withMinute(0).withSecond(0).withNano(0);
defaultTime = defaultTime.hourOfDay().setCopy(22);
defaultTime = defaultTime.minuteOfHour().setCopy(0);
defaultTime = defaultTime.secondOfMinute().setCopy(0);
long curTime = now.getMillis(); long curTime = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
long timeLeft = 0; long timeLeft = 0;
if (bane.getLiveDate() != null) if (bane.getLiveDate() != null)
timeLeft = bane.getLiveDate().getMillis() - curTime; timeLeft = bane.getLiveDate().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - curTime;
else else
timeLeft = defaultTime.getMillis() - curTime + 1000; timeLeft = defaultTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - curTime + 1000;
//DO not touch these. They are static formula's until i get the correct converter for SB Time. //DO not touch these. They are static formula's until i get the correct converter for SB Time.
writer.put((byte) placedOn.dayOfMonth().get()); writer.put((byte) placedOn.getDayOfMonth());
writer.put((byte) placedOn.monthOfYear().get()); writer.put((byte) placedOn.getMonthValue());
writer.putInt(placedOn.year().get() - 1900); writer.putInt(placedOn.getYear() - 1900);
writer.put((byte) 0); writer.put((byte) 0);
writer.put((byte) 0); writer.put((byte) 0);
writer.put((byte) 0); writer.put((byte) 0);
+27 -33
View File
@@ -19,10 +19,8 @@ import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.Protocol; import engine.net.Protocol;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate; import java.time.Duration;
import org.joda.time.DateTime; import java.time.LocalDateTime;
import org.joda.time.Period;
import org.joda.time.Seconds;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.util.ArrayList; import java.util.ArrayList;
@@ -138,7 +136,6 @@ public class ManageNPCMsg extends ClientNetMsg {
@Override @Override
protected void _serialize(ByteBufferWriter writer) { protected void _serialize(ByteBufferWriter writer) {
Period upgradePeriod;
int upgradePeriodInSeconds; int upgradePeriodInSeconds;
try { try {
@@ -200,21 +197,20 @@ public class ManageNPCMsg extends ClientNetMsg {
writer.putInt(npc.getUpgradeCost()); writer.putInt(npc.getUpgradeCost());
if (npc.isRanking() && npc.getUpgradeDateTime().isAfter(DateTime.now())) long upgradeTotalSecs = 0;
upgradePeriod = new Period(DateTime.now(), npc.getUpgradeDateTime()); if (npc.isRanking() && npc.getUpgradeDateTime().isAfter(LocalDateTime.now()))
else upgradeTotalSecs = Duration.between(LocalDateTime.now(), npc.getUpgradeDateTime()).getSeconds();
upgradePeriod = new Period(0);
writer.put((byte) upgradePeriod.getDays()); //for timer writer.put((byte) (int) (upgradeTotalSecs / 86400)); //for timer
writer.put((byte) unknown26);//unknown writer.put((byte) unknown26);//unknown
writer.putInt(100); //unknown writer.putInt(100); //unknown
writer.put((byte) upgradePeriod.getHours()); //for timer writer.put((byte) (int) ((upgradeTotalSecs % 86400) / 3600)); //for timer
writer.put((byte) upgradePeriod.getMinutes()); //for timer writer.put((byte) (int) ((upgradeTotalSecs % 3600) / 60)); //for timer
writer.put((byte) upgradePeriod.getSeconds()); //for timer writer.put((byte) (int) (upgradeTotalSecs % 60)); //for timer
if (npc.isRanking() && npc.getUpgradeDateTime().isAfter(DateTime.now())) if (npc.isRanking() && npc.getUpgradeDateTime().isAfter(LocalDateTime.now()))
upgradePeriodInSeconds = Seconds.secondsBetween(DateTime.now(), npc.getUpgradeDateTime()).getSeconds(); upgradePeriodInSeconds = (int) upgradeTotalSecs;
else else
upgradePeriodInSeconds = 0; upgradePeriodInSeconds = 0;
@@ -421,18 +417,17 @@ public class ManageNPCMsg extends ClientNetMsg {
writer.putInt(rollableSet.size()); writer.putInt(rollableSet.size());
for (int templateID : rollableSet) { for (int templateID : rollableSet) {
CObjectTemplate template = CObjectTemplate.lookup(templateID); ItemTemplate template = ItemTemplate.templates.get(templateID);
int modTable = ForgeManager.getVendorModTable(templateID);
writer.put((byte) 1); writer.put((byte) 1);
writer.putInt(0); writer.putInt(0);
writer.putInt(templateID); //itemID writer.putInt(templateID); //itemID
writer.putInt(template.getItemValue()); writer.putInt(template.item_value);
writer.putInt(600); writer.putInt(600);
writer.put((byte) 1); writer.put((byte) 1);
writer.put((byte) modTable); writer.put((byte) template.modTable);
writer.put((byte) modTable); writer.put((byte) template.modTable);
writer.put((byte) modTable); writer.put((byte) template.modTable);
writer.put((byte) modTable);//EffectItemType writer.put((byte) template.modTable);//EffectItemType
} }
ArrayList<Item> cooking = NPCManager.getAllCookingForVendor(npc); ArrayList<Item> cooking = NPCManager.getAllCookingForVendor(npc);
@@ -446,7 +441,7 @@ public class ManageNPCMsg extends ClientNetMsg {
writer.putInt(0); writer.putInt(0);
writer.putInt(item.templateID); writer.putInt(item.templateID);
writer.putInt(item.template.getItemValue()); writer.putInt(item.template.item_value);
long timeLife = item.getDateToUpgrade() - System.currentTimeMillis(); long timeLife = item.getDateToUpgrade() - System.currentTimeMillis();
@@ -591,21 +586,20 @@ public class ManageNPCMsg extends ClientNetMsg {
writer.putInt(Mob.getUpgradeCost(mobA)); writer.putInt(Mob.getUpgradeCost(mobA));
if (mobA.isRanking() && mobA.getUpgradeDateTime().isAfter(DateTime.now())) long upgradeTotalSecs = 0;
upgradePeriod = new Period(DateTime.now(), mobA.getUpgradeDateTime()); if (mobA.isRanking() && mobA.getUpgradeDateTime().isAfter(LocalDateTime.now()))
else upgradeTotalSecs = Duration.between(LocalDateTime.now(), mobA.getUpgradeDateTime()).getSeconds();
upgradePeriod = new Period(0);
writer.put((byte) upgradePeriod.getDays()); //for timer writer.put((byte) (int) (upgradeTotalSecs / 86400)); //for timer
writer.put((byte) unknown26);//unknown writer.put((byte) unknown26);//unknown
writer.putInt(100); //unknown writer.putInt(100); //unknown
writer.put((byte) upgradePeriod.getHours()); //for timer writer.put((byte) (int) ((upgradeTotalSecs % 86400) / 3600)); //for timer
writer.put((byte) upgradePeriod.getMinutes()); //for timer writer.put((byte) (int) ((upgradeTotalSecs % 3600) / 60)); //for timer
writer.put((byte) upgradePeriod.getSeconds()); //for timer writer.put((byte) (int) (upgradeTotalSecs % 60)); //for timer
if (mobA.isRanking() && mobA.getUpgradeDateTime().isAfter(DateTime.now())) if (mobA.isRanking() && mobA.getUpgradeDateTime().isAfter(LocalDateTime.now()))
upgradePeriodInSeconds = Seconds.secondsBetween(DateTime.now(), mobA.getUpgradeDateTime()).getSeconds(); upgradePeriodInSeconds = (int) upgradeTotalSecs;
else else
upgradePeriodInSeconds = 0; upgradePeriodInSeconds = 0;
@@ -54,7 +54,7 @@ public class UpdateInventoryMsg extends ClientNetMsg {
for (Item item : list) { for (Item item : list) {
if (item.template.getItemType().equals(ItemType.GOLD)) { if (item.template.item_type.equals(ItemType.GOLD)) {
if (item.getNumOfItems() == 0) if (item.getNumOfItems() == 0)
continue; continue;
} }
+1 -6
View File
@@ -16,7 +16,6 @@ import engine.net.ByteBufferWriter;
import engine.net.Protocol; import engine.net.Protocol;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.parsers.objects.DeedTemplate;
public class UseCharterMsg extends ClientNetMsg { public class UseCharterMsg extends ClientNetMsg {
@@ -62,13 +61,9 @@ public class UseCharterMsg extends ClientNetMsg {
public void configure() { public void configure() {
DeedTemplate charterDeed;
if (close) { if (close) {
for (Item i : player.getInventory()) { for (Item i : player.getInventory()) {
charterDeed = DeedTemplate._deeds.get(i.templateID); if (i.template.item_type.equals(ItemType.CHARTER)) {
if (charterDeed != null && charterDeed.item_type.equals(ItemType.CHARTER)) {
charterUUID = i.getObjectUUID(); charterUUID = i.getObjectUUID();
break; break;
} }
@@ -156,7 +156,7 @@ public class VendorBuyWindowMsg extends ClientNetMsg {
for (Item item : inventory) { for (Item item : inventory) {
if (item.getOwnerID() != ownerID) if (item.getOwnerID() != ownerID)
continue; continue;
if (item.template.getItemType().equals(ItemType.GOLD)) { if (item.template.item_type.equals(ItemType.GOLD)) {
if (item.getNumOfItems() == 0) if (item.getNumOfItems() == 0)
continue; continue;
} }
@@ -17,7 +17,7 @@ import engine.net.ByteBufferWriter;
import engine.net.Protocol; import engine.net.Protocol;
import engine.net.client.msg.ClientNetMsg; import engine.net.client.msg.ClientNetMsg;
import engine.objects.*; import engine.objects.*;
import org.joda.time.DateTime; import java.time.Instant;
public class GuildInfoMsg extends ClientNetMsg { public class GuildInfoMsg extends ClientNetMsg {
@@ -306,7 +306,7 @@ class GuildInfoMessageType4 extends GuildInfoMessageType {
writer.putString(guildLeaderName); writer.putString(guildLeaderName);
writer.putString(pc.getName()); writer.putString(pc.getName());
writer.putDateTime(DateTime.now()); writer.putDateTime(Instant.now());
writer.put((byte) 1); writer.put((byte) 1);
writer.put((byte) 1); writer.put((byte) 1);
writer.put((byte) 1); writer.put((byte) 1);
@@ -401,7 +401,7 @@ class GuildInfoMessageType5 extends GuildInfoMessageType {
writer.putString("Guild Leader"); writer.putString("Guild Leader");
writer.putString(""); //Nation Leader - I believe writer.putString(""); //Nation Leader - I believe
DateTime now = DateTime.now(); Instant now = Instant.now();
writer.putDateTime(now); writer.putDateTime(now);
writer.put((byte) 1); writer.put((byte) 1);
+49 -130
View File
@@ -29,8 +29,6 @@ import engine.net.Dispatch;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.ApplyRuneMsg; import engine.net.client.msg.ApplyRuneMsg;
import engine.net.client.msg.UpdateStateMsg; import engine.net.client.msg.UpdateStateMsg;
import engine.parsers.objects.CObjectTemplate;
import engine.parsers.objects.RuneTemplate;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import engine.powers.PowersBase; import engine.powers.PowersBase;
import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.powers.effectmodifiers.AbstractEffectModifier;
@@ -654,34 +652,16 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
AssignDefenseValue(abstractCharacter); AssignDefenseValue(abstractCharacter);
// calculate atr and damage for each hand // calculate atr and damage for each hand
ConcurrentHashMap<EquipSlotType, Item> equipped = abstractCharacter.charItemManager.getEquipped(); ConcurrentHashMap<EquipSlotType, Item> equipped = abstractCharacter.charItemManager.getEquipped();
AssignDamageAtrForPlayers(abstractCharacter, equipped.get(EquipSlotType.RHELD), true, equipped.get(EquipSlotType.LHELD)); AssignDamageAtrForPlayers(abstractCharacter, equipped.get(EquipSlotType.RHELD), true, equipped.get(EquipSlotType.RHELD));
AssignDamageAtrForPlayers(abstractCharacter, equipped.get(EquipSlotType.LHELD), false, equipped.get(EquipSlotType.RHELD)); AssignDamageAtrForPlayers(abstractCharacter, equipped.get(EquipSlotType.LHELD), false, equipped.get(EquipSlotType.LHELD));
if (abstractCharacter.getObjectType().equals(GameObjectType.Mob)) { if (abstractCharacter.getObjectType().equals(GameObjectType.Mob)) {
Mob mob = (Mob) abstractCharacter; Mob mob = (Mob) abstractCharacter;
RuneTemplate rune = RuneTemplate._runes.get(mob.loadID); abstractCharacter.minDamageHandOne = (int) mob.mobBase.getDamageMin();
float minDamage = mob.mobBase.getDamageMin(); abstractCharacter.minDamageHandTwo = (int) mob.mobBase.getDamageMin();
float maxDamage = mob.mobBase.getDamageMax(); abstractCharacter.maxDamageHandOne = (int) mob.mobBase.getDamageMax();
int attackRating = mob.mobBase.getAttackRating(); abstractCharacter.maxDamageHandTwo = (int) mob.mobBase.getDamageMax();
abstractCharacter.atrHandOne = mob.mobBase.getAttackRating();
// The client (ArcMobile, 0x46D200) takes mob damage straight from the rune MINDAMAGE/MAXDAMAGE, abstractCharacter.atrHandTwo = mob.mobBase.getAttackRating();
// with no stat scaling. Use the rune when it has damage, otherwise keep the mobbase value.
if (rune != null && rune.rune_max_damage > 0) {
minDamage = rune.rune_min_damage;
maxDamage = rune.rune_max_damage;
}
// Likewise ATR comes straight from the rune ATTACK for mobiles (0x466570).
if (rune != null && rune.rune_attack > 0)
attackRating = rune.rune_attack;
abstractCharacter.minDamageHandOne = (int) minDamage;
abstractCharacter.minDamageHandTwo = (int) minDamage;
abstractCharacter.maxDamageHandOne = (int) maxDamage;
abstractCharacter.maxDamageHandTwo = (int) maxDamage;
abstractCharacter.atrHandOne = attackRating;
abstractCharacter.atrHandTwo = attackRating;
abstractCharacter.defenseRating = mob.mobBase.getDefenseRating(); abstractCharacter.defenseRating = mob.mobBase.getDefenseRating();
} }
} }
@@ -693,17 +673,16 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
// make sure weapon exists // make sure weapon exists
boolean noWeapon = false; boolean noWeapon = false;
CObjectTemplate weaponTemplate = null; ItemTemplate weaponTemplate = null;
engine.parsers.objects.ItemTemplate.Damage damage;
if (weapon == null) if (weapon == null)
noWeapon = true; noWeapon = true;
else { else {
CObjectTemplate itemTemplate = weapon.template; ItemTemplate itemTemplate = weapon.template;
if (itemTemplate == null) if (itemTemplate == null)
noWeapon = true; noWeapon = true;
else if (!weapon.template.getItemType().equals(ItemType.WEAPON)) { else if (!weapon.template.item_type.equals(ItemType.WEAPON)) {
defaultAtrAndDamage(abstractCharacter, mainHand); defaultAtrAndDamage(abstractCharacter, mainHand);
return; return;
} else } else
@@ -720,7 +699,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
if (noWeapon) { if (noWeapon) {
if (mainHand) { if (mainHand) {
Item off = abstractCharacter.charItemManager.getEquipped().get(EquipSlotType.LHELD); Item off = abstractCharacter.charItemManager.getEquipped().get(EquipSlotType.LHELD);
if (off != null && off.template != null && off.template.getItemType().equals(ItemType.WEAPON)) if (off != null && off.template != null && off.template.item_type.equals(ItemType.WEAPON))
abstractCharacter.rangeHandOne = 10 * (1 + (abstractCharacter.statStrBase / 600)); // Set abstractCharacter.rangeHandOne = 10 * (1 + (abstractCharacter.statStrBase / 600)); // Set
// to // to
// no // no
@@ -738,24 +717,15 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
mastDam = CharacterSkill.getQuickMastery(abstractCharacter, "Unarmed Combat Mastery"); mastDam = CharacterSkill.getQuickMastery(abstractCharacter, "Unarmed Combat Mastery");
else else
mastDam = masteryPercentage; mastDam = masteryPercentage;
// Base fist damage from the race rune natural attack (1-4 for all races), scaled below like a weapon. // TODO Correct these
// Matches the client's unarmed damage calc (0x46D200). min = 1;
max = 3;
float[] naturalAttack = CombatManager.getNaturalAttack(abstractCharacter, mainHand ? EquipSlotType.RHELD : EquipSlotType.LHELD);
if (naturalAttack != null && naturalAttack.length > 9) {
min = (int) naturalAttack[8];
max = (int) naturalAttack[9];
} else {
min = 1;
max = 3;
}
} else { } else {
if (mainHand) if (mainHand)
abstractCharacter.rangeHandOne = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_max_range * (1 + (abstractCharacter.statStrBase / 600)); abstractCharacter.rangeHandOne = weapon.template.item_weapon_max_range * (1 + (abstractCharacter.statStrBase / 600));
else else
abstractCharacter.rangeHandTwo = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_max_range * (1 + (abstractCharacter.statStrBase / 600)); abstractCharacter.rangeHandTwo = weapon.template.item_weapon_max_range * (1 + (abstractCharacter.statStrBase / 600));
if (abstractCharacter.bonuses != null) { if (abstractCharacter.bonuses != null) {
float range_bonus = 1 + abstractCharacter.bonuses.getFloatPercentAll(ModType.WeaponRange, SourceType.None); float range_bonus = 1 + abstractCharacter.bonuses.getFloatPercentAll(ModType.WeaponRange, SourceType.None);
@@ -767,20 +737,20 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
} }
skillPercentage = getModifiedAmount(abstractCharacter.skills.get(weapon.template.getItemSkillUsed())); skillPercentage = getModifiedAmount(abstractCharacter.skills.get(weapon.template.item_skill_used));
masteryPercentage = getModifiedAmount(abstractCharacter.skills.get(weaponTemplate.getItemSkillMasteryUsed())); masteryPercentage = getModifiedAmount(abstractCharacter.skills.get(weaponTemplate.item_skill_mastery_used));
if (masteryPercentage == 0f) if (masteryPercentage == 0f)
mastDam = 0f; mastDam = 0f;
// mastDam = CharacterSkill.getQuickMastery(this, wb.getMastery()); // mastDam = CharacterSkill.getQuickMastery(this, wb.getMastery());
else else
mastDam = masteryPercentage; mastDam = masteryPercentage;
damage = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_damage.get(0); int[] damages = (int[]) weaponTemplate.item_weapon_damage.values().toArray()[0];
min = damage.damage_min; min = damages[0];
max = damage.damage_max; max = damages[1];
strBased = engine.parsers.objects.ItemTemplate._items.get(weapon.templateID).item_primary_attr == AttributeType.Strength; strBased = weaponTemplate.item_primary_attr.equals(AttributeType.Strength);
} }
if (abstractCharacter.effects != null && abstractCharacter.effects.containsKey("DeathShroud")) if (abstractCharacter.effects != null && abstractCharacter.effects.containsKey("DeathShroud"))
@@ -829,7 +799,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
//calculate speed //calculate speed
if (weaponTemplate != null) if (weaponTemplate != null)
speed = engine.parsers.objects.ItemTemplate.getWeapon(weaponTemplate.getTemplateId()).weapon_wepspeed; speed = weaponTemplate.item_weapon_wepspeed;
else else
speed = 20f; //unarmed attack speed speed = 20f; //unarmed attack speed
if (weapon != null) if (weapon != null)
@@ -884,12 +854,15 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
max *= percentMaxDamage; max *= percentMaxDamage;
} }
// Client (0x466EB0 sets char+0xD0C, 0x46D200 applies it): 30% cut only when both hands hold a WEAPON. //if duel wielding, cut damage by 30%
if (!noWeapon && otherHand != null && otherHand.template != null if (otherHand != null) {
&& otherHand.template.getItemType().equals(ItemType.WEAPON)) { ItemTemplate ibo = otherHand.template;
min *= 0.7f;
max *= 0.7f; if (ibo != null && otherHand.template.equals(ItemType.WEAPON)) {
min *= 0.7f;
max *= 0.7f;
}
} }
// calculate damage // calculate damage
@@ -955,7 +928,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
if (ItemManager.isShield(shield) == false) if (ItemManager.isShield(shield) == false)
return 0; return 0;
CObjectTemplate template = shield.template; ItemTemplate template = shield.template;
if (template == null) if (template == null)
return 0; return 0;
@@ -969,7 +942,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
} else } else
skillMod = blockSkill.getModifiedAmount(); skillMod = blockSkill.getModifiedAmount();
float def = engine.parsers.objects.ItemTemplate._items.get(shield.templateID).item_defense_rating; float def = template.item_defense_rating;
//apply item defense bonuses //apply item defense bonuses
@@ -991,30 +964,29 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
if (armor == null) if (armor == null)
return 0; return 0;
CObjectTemplate template = armor.template; ItemTemplate template = armor.template;
if (template == null) if (template == null)
return 0; return 0;
if (!armor.template.getItemType().equals(ItemType.ARMOR)) if (!armor.template.item_type.equals(ItemType.ARMOR))
return 0; return 0;
// "Cloth" is a placeholder in Skills.cfg (token 0) that no character learns if (armor.template.item_skill_used.isEmpty())
if (armor.template.getItemSkillUsed().isEmpty() || armor.template.getItemSkillUsed().equals("Cloth")) return template.item_defense_rating;
return engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_defense_rating;
CharacterSkill armorSkill = abstractCharacter.skills.get(armor.template.getItemSkillUsed()); CharacterSkill armorSkill = abstractCharacter.skills.get(armor.template.item_skill_used);
if (abstractCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) && armorSkill == null) { if (abstractCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) && armorSkill == null) {
Logger.error("Player " + abstractCharacter.getObjectUUID() Logger.error("Player " + abstractCharacter.getObjectUUID()
+ " has armor equipped without the nescessary skill to equip it"); + " has armor equipped without the nescessary skill to equip it");
return engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_defense_rating; return template.item_defense_rating;
} }
if (armorSkill == null) if (armorSkill == null)
return engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_defense_rating; // Mobiles do not have armor skills @TODO return template.item_defense_rating; // Mobiles do not have armor skills @TODO
float def = engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_defense_rating; float def = template.item_defense_rating;
//apply item defense bonuses //apply item defense bonuses
@@ -1032,7 +1004,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
private static float getWeaponDefense(AbstractCharacter abstractCharacter, ConcurrentHashMap<EquipSlotType, Item> equipped) { private static float getWeaponDefense(AbstractCharacter abstractCharacter, ConcurrentHashMap<EquipSlotType, Item> equipped) {
Item weapon = equipped.get(EquipSlotType.RHELD); Item weapon = equipped.get(EquipSlotType.RHELD);
CObjectTemplate weaponTemplate = null; ItemTemplate weaponTemplate = null;
CharacterSkill skill, mastery; CharacterSkill skill, mastery;
float val = 0; float val = 0;
boolean unarmed = false; boolean unarmed = false;
@@ -1053,8 +1025,8 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
skill = abstractCharacter.skills.get("Unarmed Combat"); skill = abstractCharacter.skills.get("Unarmed Combat");
mastery = abstractCharacter.skills.get("Unarmed Combat Mastery"); mastery = abstractCharacter.skills.get("Unarmed Combat Mastery");
} else { } else {
skill = abstractCharacter.skills.get(weapon.template.getItemSkillUsed()); skill = abstractCharacter.skills.get(weapon.template.item_skill_used);
mastery = abstractCharacter.skills.get(weaponTemplate.getItemSkillMasteryUsed()); mastery = abstractCharacter.skills.get(weaponTemplate.item_skill_mastery_used);
} }
if (skill != null) if (skill != null)
@@ -1089,7 +1061,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
for (Item item : equipped.values()) { for (Item item : equipped.values()) {
CObjectTemplate ib = item.template; ItemTemplate ib = item.template;
if (ib == null) if (ib == null)
continue; continue;
@@ -1504,22 +1476,13 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
Mob mob = (Mob) this; Mob mob = (Mob) this;
if (mob.isSiege()) { if (mob.isSiege()) {
return CombatManager.getSiegeRange(mob); return 300;
} }
float range = 8; float range = 8;
if ((this).charItemManager.equipped.get(EquipSlotType.RHELD) != null) { if ((this).charItemManager.equipped.get(EquipSlotType.RHELD) != null) {
range = engine.parsers.objects.ItemTemplate.getWeapon(((Mob) this).charItemManager.equipped.get(EquipSlotType.RHELD).templateID).weapon_max_range; range = ((Mob) this).charItemManager.equipped.get(EquipSlotType.RHELD).template.item_weapon_max_range;
} else if (((Mob) this).charItemManager.equipped.get(EquipSlotType.LHELD) != null) { } else if (((Mob) this).charItemManager.equipped.get(EquipSlotType.LHELD) != null) {
range = engine.parsers.objects.ItemTemplate.getWeapon(((Mob) this).charItemManager.equipped.get(EquipSlotType.LHELD).templateID).weapon_max_range; range = ((Mob) this).charItemManager.equipped.get(EquipSlotType.LHELD).template.item_weapon_max_range;
} else {
// Unarmed: use the rune natural attack range when it has one (e.g. Gasser 150), not clamped.
// Most melee runes have 0, so they keep the default of 8.
float naturalRange = CombatManager.getNaturalAttackRange(mob, EquipSlotType.RHELD);
if (naturalRange > 0)
return naturalRange;
} }
// TODO Is this clamp from live? // TODO Is this clamp from live?
@@ -1864,15 +1827,6 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
if (this.getObjectType().equals(GameObjectType.Mob)) { if (this.getObjectType().equals(GameObjectType.Mob)) {
//handle hate value addition //handle hate value addition
Mob target = (Mob) this; Mob target = (Mob) this;
// Siege engines switch to whoever damages them, players and pets alike.
// Misses and non-damaging powers do not pull them.
if (target.isSiege() && value < 0f && attacker != null && !attacker.equals(target)) {
target.setCombatTarget(attacker);
flagSiegeAttackerHostile(target, attacker);
}
if (attacker.getObjectType().equals(GameObjectType.PlayerCharacter)) { if (attacker.getObjectType().equals(GameObjectType.PlayerCharacter)) {
if (target.playerAgroMap.containsKey(attacker.getObjectUUID())) if (target.playerAgroMap.containsKey(attacker.getObjectUUID()))
@@ -1906,41 +1860,6 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
return 0; return 0;
} }
private static void flagSiegeAttackerHostile(Mob siegeEngine, AbstractCharacter attacker) {
// Damaging a siege engine on a city grid flags the player hostile to that
// city, unless they belong to the city's nation or an allied nation.
// Pets flag their owner.
City city;
AbstractCharacter flagged;
Guild cityNation;
city = ZoneManager.getCityAtLocation(siegeEngine.loc);
if (city == null)
return;
flagged = attacker;
if (attacker.getObjectType().equals(GameObjectType.Mob))
flagged = ((Mob) attacker).guardCaptain;
if (flagged == null || !flagged.getObjectType().equals(GameObjectType.PlayerCharacter))
return;
cityNation = city.getGuild().getNation();
if (flagged.getGuild().getNation().equals(cityNation))
return;
if (cityNation.getAllyList().contains(flagged.getGuild().getNation()))
return;
if (!city.cityOutlaws.contains(flagged.getObjectUUID()))
city.cityOutlaws.add(flagged.getObjectUUID());
}
public float getCurrentHitpoints() { public float getCurrentHitpoints() {
return this.health.get(); return this.health.get();
} }
@@ -148,20 +148,9 @@ public abstract class AbstractIntelligenceAgent extends AbstractCharacter {
public void dismiss() { public void dismiss() {
boolean isSiegeEngine;
isSiegeEngine = this.getObjectType() == GameObjectType.Mob && ((Mob) this).isSiege();
if (this.isPet()) { if (this.isPet()) {
if (isSiegeEngine) { if ((this.agentType.equals(mbEnums.AIAgentType.PET))) { //delete summoned pet
// Released siege engines stay in place, alive, and keep firing at
// their current target until a Rod of Command takes them again.
this.agentType = mbEnums.AIAgentType.MOBILE;
} else if ((this.agentType.equals(mbEnums.AIAgentType.PET))) { //delete summoned pet
WorldGrid.RemoveWorldObject(this); WorldGrid.RemoveWorldObject(this);
@@ -178,8 +167,7 @@ public abstract class AbstractIntelligenceAgent extends AbstractCharacter {
// clear owner and set not alive // clear owner and set not alive
if (!isSiegeEngine) this.isAlive.set(false);
this.isAlive.set(false);
PlayerCharacter owner = (PlayerCharacter) this.guardCaptain; PlayerCharacter owner = (PlayerCharacter) this.guardCaptain;
@@ -200,8 +188,6 @@ public abstract class AbstractIntelligenceAgent extends AbstractCharacter {
this.guardCaptain = null; this.guardCaptain = null;
} }
if (isSiegeEngine && this.isAlive())
WorldGrid.updateObject(this);
} }
} }
+3 -3
View File
@@ -172,7 +172,7 @@ public class Account extends AbstractGameObject {
this.vault = DbManager.ItemQueries.GET_ITEMS_FOR_ACCOUNT(this.getObjectUUID()); this.vault = DbManager.ItemQueries.GET_ITEMS_FOR_ACCOUNT(this.getObjectUUID());
for (Item item : this.vault) { for (Item item : this.vault) {
if (item.template.getItemType().equals(mbEnums.ItemType.GOLD)) { if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) {
this.vaultGold = item; this.vaultGold = item;
} }
} }
@@ -216,7 +216,7 @@ public class Account extends AbstractGameObject {
return; return;
if (item.containerType == mbEnums.ItemContainerType.INVENTORY && player.charItemManager.isVaultOpen()) { if (item.containerType == mbEnums.ItemContainerType.INVENTORY && player.charItemManager.isVaultOpen()) {
if (!player.charItemManager.hasRoomVault(item.template.getItemWt())) { if (!player.charItemManager.hasRoomVault(item.template.item_wt)) {
ItemToVaultMsgHandler.forceTransferFromVaultToInventory(msg, origin, "There is no room in your vault."); ItemToVaultMsgHandler.forceTransferFromVaultToInventory(msg, origin, "There is no room in your vault.");
return; return;
} }
@@ -262,7 +262,7 @@ public class Account extends AbstractGameObject {
return; return;
if (item.containerType == mbEnums.ItemContainerType.VAULT && itemManager.isVaultOpen()) { if (item.containerType == mbEnums.ItemContainerType.VAULT && itemManager.isVaultOpen()) {
if (!itemManager.hasRoomInventory(item.template.getItemWt())) { if (!itemManager.hasRoomInventory(item.template.item_wt)) {
ItemFromVaultMsgHandler.forceTransferFromInventoryToVault(msg, origin, "There is no room in your inventory."); ItemFromVaultMsgHandler.forceTransferFromInventoryToVault(msg, origin, "There is no room in your inventory.");
return; return;
} }
+18 -22
View File
@@ -25,7 +25,8 @@ import engine.net.client.ClientConnection;
import engine.net.client.msg.PlaceAssetMsg; import engine.net.client.msg.PlaceAssetMsg;
import engine.net.client.msg.chat.ChatSystemMsg; import engine.net.client.msg.chat.ChatSystemMsg;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import java.time.LocalDateTime;
import java.time.ZoneId;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
@@ -40,8 +41,8 @@ public final class Bane {
private final int cityUUID; private final int cityUUID;
private final int stoneUUID; private final int stoneUUID;
private int ownerUUID; private int ownerUUID;
private DateTime placementDate = null; private LocalDateTime placementDate = null;
private DateTime liveDate = null; private LocalDateTime liveDate = null;
private BaneDefaultTimeJob defaultTimeJob; private BaneDefaultTimeJob defaultTimeJob;
// Internal cache for banes // Internal cache for banes
@@ -62,12 +63,12 @@ public final class Bane {
sqlDateTime = rs.getTimestamp("placementDate"); sqlDateTime = rs.getTimestamp("placementDate");
if (sqlDateTime != null) if (sqlDateTime != null)
this.placementDate = new DateTime(sqlDateTime); this.placementDate = LocalDateTime.ofInstant(sqlDateTime.toInstant(), ZoneId.systemDefault());
sqlDateTime = rs.getTimestamp("liveDate"); sqlDateTime = rs.getTimestamp("liveDate");
if (sqlDateTime != null) if (sqlDateTime != null)
this.liveDate = new DateTime(sqlDateTime); this.liveDate = LocalDateTime.ofInstant(sqlDateTime.toInstant(), ZoneId.systemDefault());
switch (this.getSiegePhase()) { switch (this.getSiegePhase()) {
@@ -81,7 +82,7 @@ public final class Bane {
this.activateBaneJob.cancelJob(); this.activateBaneJob.cancelJob();
abtj = new ActivateBaneJob(cityUUID); abtj = new ActivateBaneJob(cityUUID);
JobScheduler.getInstance().scheduleJob(abtj, this.liveDate.getMillis()); JobScheduler.getInstance().scheduleJob(abtj, this.liveDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
this.activateBaneJob = abtj; this.activateBaneJob = abtj;
break; break;
@@ -93,7 +94,7 @@ public final class Bane {
this.activateBaneJob.cancelJob(); this.activateBaneJob.cancelJob();
abtj = new ActivateBaneJob(cityUUID); abtj = new ActivateBaneJob(cityUUID);
JobScheduler.getInstance().scheduleJob(abtj, this.liveDate.getMillis()); JobScheduler.getInstance().scheduleJob(abtj, this.liveDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
this.activateBaneJob = abtj; this.activateBaneJob = abtj;
break; break;
@@ -353,7 +354,7 @@ public final class Bane {
return phase; return phase;
} }
if (DateTime.now().isAfter(this.liveDate)) { if (LocalDateTime.now().isAfter(this.liveDate)) {
phase = SiegePhase.WAR; //war phase = SiegePhase.WAR; //war
return phase; return phase;
} }
@@ -368,15 +369,10 @@ public final class Bane {
private void setDefaultTime() { private void setDefaultTime() {
DateTime timeToSetDefault = new DateTime(this.placementDate); LocalDateTime timeToSetDefault = this.placementDate.plusDays(1);
timeToSetDefault = timeToSetDefault.plusDays(1);
DateTime currentTime = DateTime.now(); LocalDateTime currentTime = LocalDateTime.now();
DateTime defaultTime = new DateTime(this.placementDate); LocalDateTime defaultTime = this.placementDate.plusDays(2).withHour(22).withMinute(0).withSecond(0);
defaultTime = defaultTime.plusDays(2);
defaultTime = defaultTime.hourOfDay().setCopy(22);
defaultTime = defaultTime.minuteOfHour().setCopy(0);
defaultTime = defaultTime.secondOfMinute().setCopy(0);
if (currentTime.isAfter(timeToSetDefault)) if (currentTime.isAfter(timeToSetDefault))
this.setLiveDate(defaultTime); this.setLiveDate(defaultTime);
@@ -386,7 +382,7 @@ public final class Bane {
this.defaultTimeJob.cancelJob(); this.defaultTimeJob.cancelJob();
BaneDefaultTimeJob bdtj = new BaneDefaultTimeJob(this); BaneDefaultTimeJob bdtj = new BaneDefaultTimeJob(this);
JobScheduler.getInstance().scheduleJob(bdtj, timeToSetDefault.getMillis()); JobScheduler.getInstance().scheduleJob(bdtj, timeToSetDefault.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
this.defaultTimeJob = bdtj; this.defaultTimeJob = bdtj;
} }
} }
@@ -453,7 +449,7 @@ public final class Bane {
return true; return true;
} }
public final DateTime getPlacementDate() { public final LocalDateTime getPlacementDate() {
return placementDate; return placementDate;
} }
@@ -462,14 +458,14 @@ public final class Bane {
return (this.getSiegePhase() != SiegePhase.CHALLENGE); return (this.getSiegePhase() != SiegePhase.CHALLENGE);
} }
public final DateTime getLiveDate() { public final LocalDateTime getLiveDate() {
return liveDate; return liveDate;
} }
public void setLiveDate(DateTime baneTime) { public void setLiveDate(LocalDateTime baneTime) {
if (DbManager.BaneQueries.SET_BANE_TIME(baneTime, this.getCity().getObjectUUID())) { if (DbManager.BaneQueries.SET_BANE_TIME(baneTime, this.getCity().getObjectUUID())) {
this.liveDate = new DateTime(baneTime); this.liveDate = baneTime;
// Push event to warehouse // Push event to warehouse
@@ -511,7 +507,7 @@ public final class Bane {
ActivateBaneJob abtj = new ActivateBaneJob(cityUUID); ActivateBaneJob abtj = new ActivateBaneJob(cityUUID);
JobScheduler.getInstance().scheduleJob(abtj, this.liveDate.getMillis()); JobScheduler.getInstance().scheduleJob(abtj, this.liveDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
this.activateBaneJob = abtj; this.activateBaneJob = abtj;
} else { } else {
Logger.debug("error with city " + this.getCity().getName()); Logger.debug("error with city " + this.getCity().getName());
+3 -41
View File
@@ -10,11 +10,7 @@
package engine.objects; package engine.objects;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.mbEnums;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.parsers.objects.RuneTemplate;
import engine.util.Hasher;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -102,48 +98,14 @@ public class BaseClass extends AbstractGameObject {
this.healthMod = rs.getInt("healthMod"); this.healthMod = rs.getInt("healthMod");
this.manaMod = rs.getInt("manaMod"); this.manaMod = rs.getInt("manaMod");
this.staminaMod = rs.getInt("staminaMod"); this.staminaMod = rs.getInt("staminaMod");
this.skillsGranted = SkillReq.getSkillReqsForRune(this.getObjectUUID()); this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(this.getObjectUUID());
this.powersGranted = PowerReq.getPowerReqsForRune(this.getObjectUUID()); this.powersGranted = PowerReq.getPowerReqsForRune(this.getObjectUUID());
this.effectsList = MobBaseEffects.getEffectsForRune(this.getObjectUUID()); this.effectsList = (DbManager.MobBaseQueries.GET_RUNEBASE_EFFECTS(this.getObjectUUID()));
} }
/**
* Rune Template Constructor
*/
public BaseClass(RuneTemplate rune) {
super(rune.template_id);
this.name = rune.obj_name;
this.description = rune.rune_dsc;
this.strMod = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Strength, 0).byteValue();
this.dexMod = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Dexterity, 0).byteValue();
this.conMod = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Constitution, 0).byteValue();
this.intMod = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Intelligence, 0).byteValue();
this.spiMod = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Spirit, 0).byteValue();
this.token = Hasher.SBStringHash(rune.rune_sub_type);
this.healthMod = rune.rune_health;
this.manaMod = rune.rune_mana;
this.staminaMod = rune.rune_stamina;
this.skillsGranted = SkillReq.getSkillReqsForRune(this.getObjectUUID());
this.powersGranted = PowerReq.getPowerReqsForRune(this.getObjectUUID());
this.effectsList = MobBaseEffects.getEffectsForRune(this.getObjectUUID());
}
public static void LoadAllBaseClasses() { public static void LoadAllBaseClasses() {
DbManager.BaseClassQueries.GET_ALL_BASE_CLASSES();
int loadedCount = 0;
// Promotion classes and the Pet class are also CLASS runes, but not standard creation runes
for (RuneTemplate rune : RuneTemplate._runes.values()) {
if (rune.rune_type != mbEnums.RuneType.CLASS || !rune.rune_is_standard_character_creation)
continue;
DbManager.addToCache(new BaseClass(rune));
loadedCount++;
}
Logger.info("Loaded " + loadedCount + " base classes from runes");
} }
public static void serializeForClientMsg(BaseClass baseClass, ByteBufferWriter writer) { public static void serializeForClientMsg(BaseClass baseClass, ByteBufferWriter writer) {
+1 -4
View File
@@ -395,10 +395,8 @@ public class Building extends AbstractWorldObject {
//friendly building has been attacked, add attacker to city outlaw list //friendly building has been attacked, add attacker to city outlaw list
if (!playerCity.cityOutlaws.contains(attacker.getObjectUUID()) && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)) if (!playerCity.cityOutlaws.contains(attacker.getObjectUUID()) && attacker.getObjectType().equals(GameObjectType.PlayerCharacter))
playerCity.cityOutlaws.add(attacker.getObjectUUID()); playerCity.cityOutlaws.add(attacker.getObjectUUID());
//only city guards respond; siege engines and pets in the zone are left alone
for (Mob guard : playerCity.getParent().zoneMobSet) for (Mob guard : playerCity.getParent().zoneMobSet)
if (guard.isPlayerGuard() && guard.combatTarget == null) if (guard.combatTarget == null)
guard.setCombatTarget(attacker); guard.setCombatTarget(attacker);
} }
} }
@@ -433,7 +431,6 @@ public class Building extends AbstractWorldObject {
// Special handling of warehouses // Special handling of warehouses
if (blueprint.getBuildingGroup() == BuildingGroup.WAREHOUSE) { if (blueprint.getBuildingGroup() == BuildingGroup.WAREHOUSE) {
Warehouse.destroyedWarehouses.put(this.getObjectUUID(), city.warehouse);
DbManager.WarehouseQueries.DELETE_WAREHOUSE(city.warehouse); DbManager.WarehouseQueries.DELETE_WAREHOUSE(city.warehouse);
city.warehouse = null; city.warehouse = null;
} }
+33 -34
View File
@@ -17,7 +17,6 @@ import engine.mbEnums.ItemType;
import engine.net.Dispatch; import engine.net.Dispatch;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.*; import engine.net.client.msg.*;
import engine.parsers.objects.CObjectTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -131,19 +130,19 @@ public class CharacterItemManager {
this.equipped.put(i.equipSlot, i); this.equipped.put(i.equipSlot, i);
break; break;
case BANK: case BANK:
if (i.template.getItemType().equals(ItemType.GOLD)) if (i.template.item_type.equals(ItemType.GOLD))
this.goldBank = i; this.goldBank = i;
else if (this.bank.contains(i) == false) else if (this.bank.contains(i) == false)
this.bank.add(i); this.bank.add(i);
break; break;
case INVENTORY: case INVENTORY:
if (i.template.getItemType().equals(ItemType.GOLD)) if (i.template.item_type.equals(ItemType.GOLD))
this.goldInventory = i; this.goldInventory = i;
else if (this.inventory.contains(i) == false) else if (this.inventory.contains(i) == false)
this.inventory.add(i); this.inventory.add(i);
break; break;
case VAULT: case VAULT:
if (i.template.getItemType().equals(ItemType.GOLD)) if (i.template.item_type.equals(ItemType.GOLD))
this.goldVault = i; this.goldVault = i;
else if (this.vault.contains(i) == false) else if (this.vault.contains(i) == false)
this.vault.add(i); this.vault.add(i);
@@ -176,13 +175,13 @@ public class CharacterItemManager {
this.equipped.put(i.equipSlot, i); this.equipped.put(i.equipSlot, i);
break; break;
case BANK: case BANK:
if (i.template.getItemType().equals(ItemType.GOLD)) if (i.template.item_type.equals(ItemType.GOLD))
this.goldBank = i; this.goldBank = i;
else if (this.bank.contains(i) == false) else if (this.bank.contains(i) == false)
this.bank.add(i); this.bank.add(i);
break; break;
case INVENTORY: case INVENTORY:
if (i.template.getItemType().equals(ItemType.GOLD)) if (i.template.item_type.equals(ItemType.GOLD))
this.goldInventory = i; this.goldInventory = i;
else if (this.inventory.contains(i) == false) else if (this.inventory.contains(i) == false)
this.inventory.add(i); this.inventory.add(i);
@@ -512,7 +511,7 @@ public class CharacterItemManager {
if (i == null) if (i == null)
return false; return false;
if (i.template.getItemType().equals(ItemType.GOLD)) { if (i.template.item_type.equals(ItemType.GOLD)) {
if (this.getGoldInventory() != null) { if (this.getGoldInventory() != null) {
if (i.getObjectUUID() == this.getGoldInventory().getObjectUUID()) if (i.getObjectUUID() == this.getGoldInventory().getObjectUUID())
this.goldInventory = null; this.goldInventory = null;
@@ -542,7 +541,7 @@ public class CharacterItemManager {
} }
private synchronized boolean junk(Item i, boolean updateInventory) { private synchronized boolean junk(Item i, boolean updateInventory) {
if (i.template.getItemType().equals(ItemType.GOLD)) { if (i.template.item_type.equals(ItemType.GOLD)) {
if (this.getGoldInventory().getObjectUUID() == i.getObjectUUID()) if (this.getGoldInventory().getObjectUUID() == i.getObjectUUID())
if (DbManager.ItemQueries.UPDATE_GOLD(i, 0)) { if (DbManager.ItemQueries.UPDATE_GOLD(i, 0)) {
this.getGoldInventory().setNumOfItems(0); this.getGoldInventory().setNumOfItems(0);
@@ -597,7 +596,7 @@ public class CharacterItemManager {
if (equippedContains(item)) { if (equippedContains(item)) {
fromEquip = true; fromEquip = true;
if (item.template.getItemType().equals(ItemType.GOLD)) if (item.template.item_type.equals(ItemType.GOLD))
this.absCharacter.cancelOnUnEquip(); this.absCharacter.cancelOnUnEquip();
} }
@@ -815,7 +814,7 @@ public class CharacterItemManager {
// This removes ingame item from inventory for loot. // This removes ingame item from inventory for loot.
private synchronized boolean removeItemFromInventory(Item i) { private synchronized boolean removeItemFromInventory(Item i) {
if (i.template.getItemType().equals(ItemType.GOLD)) { if (i.template.item_type.equals(ItemType.GOLD)) {
if (i.getObjectUUID() != this.getGoldInventory().getObjectUUID()) if (i.getObjectUUID() != this.getGoldInventory().getObjectUUID())
return false; return false;
if (!DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, 0)) { if (!DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, 0)) {
@@ -838,7 +837,7 @@ public class CharacterItemManager {
// This adds item to inventory for loot. Validity checks already handled // This adds item to inventory for loot. Validity checks already handled
public synchronized boolean addItemToInventory(Item i) { public synchronized boolean addItemToInventory(Item i) {
if (i.template.getItemType().equals(ItemType.GOLD)) if (i.template.item_type.equals(ItemType.GOLD))
if (this.absCharacter.getObjectType() == GameObjectType.Mob) { if (this.absCharacter.getObjectType() == GameObjectType.Mob) {
if (this.goldInventory == null) if (this.goldInventory == null)
loadGoldItems(); loadGoldItems();
@@ -857,7 +856,7 @@ public class CharacterItemManager {
this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal()); this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal());
if (i.template != null) if (i.template != null)
this.inventoryWeight += i.template.getItemWt(); this.inventoryWeight += i.template.item_wt;
return true; return true;
} }
@@ -1042,7 +1041,7 @@ public class CharacterItemManager {
if (npc.getContractID() >= 1900 && npc.getContractID() <= 1906) if (npc.getContractID() >= 1900 && npc.getContractID() <= 1906)
eatItem = true; eatItem = true;
if (itemToSell.template.getItemType().equals(ItemType.POTION)) if (itemToSell.template.item_type.equals(ItemType.POTION))
eatItem = true; eatItem = true;
if (eatItem) { if (eatItem) {
@@ -1086,14 +1085,14 @@ public class CharacterItemManager {
synchronized (this) { synchronized (this) {
synchronized (itemMan) { synchronized (itemMan) {
CObjectTemplate template = purchasedItem.template; ItemTemplate template = purchasedItem.template;
if (template == null) if (template == null)
return false; return false;
//test inventory is not full //test inventory is not full
if (!hasRoomInventory(template.getItemWt())) if (!hasRoomInventory(template.item_wt))
return false; return false;
if (!itemMan.inventory.contains(purchasedItem)) if (!itemMan.inventory.contains(purchasedItem))
@@ -1106,8 +1105,8 @@ public class CharacterItemManager {
// Reset value // Reset value
purchasedItem.value = (int) (purchasedItem.template.getItemValue() * (purchasedItem.combat_health_current / purchasedItem.template.getCombatHealthFull())); purchasedItem.value = (int) (purchasedItem.template.item_value * (purchasedItem.combat_health_current / purchasedItem.template.combat_health_full));
purchasedItem.magicValue = purchasedItem.template.getItemValue() + purchasedItem.calcMagicValue(); purchasedItem.magicValue = purchasedItem.template.item_value + purchasedItem.calcMagicValue();
// db transfer successfully, remove from this character // db transfer successfully, remove from this character
// skip this check if this is a mobLoot item (which is not in any inventory) // skip this check if this is a mobLoot item (which is not in any inventory)
@@ -1185,9 +1184,9 @@ public class CharacterItemManager {
synchronized (lockFirst) { synchronized (lockFirst) {
synchronized (lockSecond) { synchronized (lockSecond) {
// make sure current player has item in inventory // make sure current player has item in inventory
if (lootItem.template.getItemType().equals(ItemType.GOLD) && lootItem.getObjectUUID() != this.getGoldInventory().getObjectUUID() && !(this.absCharacter.getObjectType().equals(GameObjectType.Mob))) if (lootItem.template.item_type.equals(ItemType.GOLD) && lootItem.getObjectUUID() != this.getGoldInventory().getObjectUUID() && !(this.absCharacter.getObjectType().equals(GameObjectType.Mob)))
return null; return null;
else if (!this.inventory.contains(lootItem) && !this.equipped.containsValue(lootItem) && !lootItem.template.getItemType().equals(ItemType.GOLD)) else if (!this.inventory.contains(lootItem) && !this.equipped.containsValue(lootItem) && !lootItem.template.item_type.equals(ItemType.GOLD))
return null; return null;
// get weight of item // get weight of item
@@ -1195,13 +1194,13 @@ public class CharacterItemManager {
if (lootItem.template == null) if (lootItem.template == null)
return null; return null;
int weight = lootItem.template.getItemWt(); int weight = lootItem.template.item_wt;
// make sure lootingPlayer has room for item // make sure lootingPlayer has room for item
if (!lootItem.template.getItemType().equals(ItemType.GOLD) && !looterItems.hasRoomInventory(weight)) if (!lootItem.template.item_type.equals(ItemType.GOLD) && !looterItems.hasRoomInventory(weight))
return null; return null;
if (lootItem.template.getItemType().equals(ItemType.GOLD)) if (lootItem.template.item_type.equals(ItemType.GOLD))
if (amount != -1) { //from steal if (amount != -1) { //from steal
int total = lootItem.getNumOfItems(); int total = lootItem.getNumOfItems();
amount = (amount > total) ? total : amount; amount = (amount > total) ? total : amount;
@@ -1264,19 +1263,19 @@ public class CharacterItemManager {
* Delegates * Delegates
*/ */
public synchronized boolean bankContains(Item item) { public synchronized boolean bankContains(Item item) {
if (item.template.getItemType().equals(ItemType.GOLD)) if (item.template.item_type.equals(ItemType.GOLD))
return (this.getGoldBank() != null && this.goldBank.getObjectUUID() == item.getObjectUUID()); return (this.getGoldBank() != null && this.goldBank.getObjectUUID() == item.getObjectUUID());
return bank.contains(item); return bank.contains(item);
} }
public synchronized boolean inventoryContains(Item item) { public synchronized boolean inventoryContains(Item item) {
if (item.template.getItemType().equals(ItemType.GOLD)) if (item.template.item_type.equals(ItemType.GOLD))
return (this.getGoldInventory() != null && this.goldInventory.getObjectUUID() == item.getObjectUUID()); return (this.getGoldInventory() != null && this.goldInventory.getObjectUUID() == item.getObjectUUID());
return inventory.contains(item); return inventory.contains(item);
} }
public synchronized boolean vaultContains(Item item) { public synchronized boolean vaultContains(Item item) {
if (item.template.getItemType().equals(ItemType.GOLD)) if (item.template.item_type.equals(ItemType.GOLD))
return (this.getGoldVault() != null && this.goldVault.getObjectUUID() == item.getObjectUUID()); return (this.getGoldVault() != null && this.goldVault.getObjectUUID() == item.getObjectUUID());
return this.account.getVault().contains(item); return this.account.getVault().contains(item);
} }
@@ -1519,13 +1518,13 @@ public class CharacterItemManager {
item.zeroItem(); item.zeroItem();
item.containerType = mbEnums.ItemContainerType.INVENTORY; item.containerType = mbEnums.ItemContainerType.INVENTORY;
if (item.template.getItemType().equals(ItemType.GOLD)) if (item.template.item_type.equals(ItemType.GOLD))
//only add gold item once //only add gold item once
if (!corpse.hasGold()) if (!corpse.hasGold())
corpse.setHasGold(true); corpse.setHasGold(true);
newInventory.add(item); newInventory.add(item);
} else //item } else //item
if (item.template.getItemType().equals(ItemType.GOLD)) { if (item.template.item_type.equals(ItemType.GOLD)) {
int amt = item.getNumOfItems(); int amt = item.getNumOfItems();
item.setNumOfItems(0); item.setNumOfItems(0);
MobLoot ml = new MobLoot(this.absCharacter, amt); MobLoot ml = new MobLoot(this.absCharacter, amt);
@@ -1677,7 +1676,7 @@ public class CharacterItemManager {
if (item == null) if (item == null)
continue; continue;
weight += item.template.getItemWt(); weight += item.template.item_wt;
} }
return weight; return weight;
} }
@@ -1697,7 +1696,7 @@ public class CharacterItemManager {
this.bankWeight = 0; this.bankWeight = 0;
for (Item item : this.bank) { for (Item item : this.bank) {
if (item.template != null) if (item.template != null)
this.bankWeight += item.template.getItemWt(); this.bankWeight += item.template.item_wt;
} }
} }
@@ -1708,7 +1707,7 @@ public class CharacterItemManager {
while (it.hasNext()) { while (it.hasNext()) {
Item item = it.next(); Item item = it.next();
if (item.template != null) if (item.template != null)
this.equipWeight += item.template.getItemWt(); this.equipWeight += item.template.item_wt;
} }
} }
@@ -1716,7 +1715,7 @@ public class CharacterItemManager {
this.inventoryWeight = 0; this.inventoryWeight = 0;
for (Item item : this.inventory) { for (Item item : this.inventory) {
if (item.template != null) if (item.template != null)
this.inventoryWeight += item.template.getItemWt(); this.inventoryWeight += item.template.item_wt;
} }
} }
@@ -1724,7 +1723,7 @@ public class CharacterItemManager {
this.vaultWeight = 0; this.vaultWeight = 0;
for (Item item : this.vault) { for (Item item : this.vault) {
if (item.template != null) if (item.template != null)
this.vaultWeight += item.template.getItemWt(); this.vaultWeight += item.template.item_wt;
} }
} }
@@ -1756,7 +1755,7 @@ public class CharacterItemManager {
return; return;
if (!item.moveItemToInventory(player)) if (!item.moveItemToInventory(player))
Logger.error("templateL " + item.template.getTemplateId()); Logger.error("templateL " + item.template.template_id);
// remove it from other lists: // remove it from other lists:
this.remItemFromLists(item); this.remItemFromLists(item);
@@ -1933,7 +1932,7 @@ public class CharacterItemManager {
return; return;
//don't damage noob gear, hair or beards. //don't damage noob gear, hair or beards.
if (item.template.getCombatHealthFull() == 0) if (item.template.combat_health_full == 0)
return; return;
if (!item.isCanDestroy()) if (!item.isCanDestroy())
+1 -1
View File
@@ -334,7 +334,7 @@ public class CharacterPower extends AbstractGameObject {
// return pc.getBonuses().getByte("gt." + this.power.getToken()); // return pc.getBonuses().getByte("gt." + this.power.getToken());
// } else // } else
// return pc.getBonuses().getByte("gt." + this.power.getToken()); // return pc.getBonuses().getByte("gt." + this.power.getToken());
return PowerGrantedTrains.getGrantedTrains(this.power.getToken(), pc); return PowerGrant.getGrantedTrains(this.power.getToken(), pc);
} else } else
return 0; return 0;
} }
+3 -3
View File
@@ -37,7 +37,7 @@ public class CharacterRune extends AbstractGameObject {
this.runeBase = runeBase; this.runeBase = runeBase;
this.player = characterID; this.player = characterID;
if (this.runeBase != null) { if (this.runeBase != null) {
this.skillsGranted = SkillReq.getSkillReqsForRune(this.runeBase.getObjectUUID()); this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(this.runeBase.getObjectUUID());
this.powersGranted = PowerReq.getPowerReqsForRune(this.runeBase.getObjectUUID()); this.powersGranted = PowerReq.getPowerReqsForRune(this.runeBase.getObjectUUID());
} else { } else {
this.skillsGranted = new ArrayList<>(); this.skillsGranted = new ArrayList<>();
@@ -57,7 +57,7 @@ public class CharacterRune extends AbstractGameObject {
this.runeBase = runeBase; this.runeBase = runeBase;
this.player = characterID; this.player = characterID;
if (this.runeBase != null) { if (this.runeBase != null) {
this.skillsGranted = SkillReq.getSkillReqsForRune(this.runeBase.getObjectUUID()); this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(this.runeBase.getObjectUUID());
this.powersGranted = PowerReq.getPowerReqsForRune(this.runeBase.getObjectUUID()); this.powersGranted = PowerReq.getPowerReqsForRune(this.runeBase.getObjectUUID());
} else { } else {
this.skillsGranted = new ArrayList<>(); this.skillsGranted = new ArrayList<>();
@@ -78,7 +78,7 @@ public class CharacterRune extends AbstractGameObject {
this.runeBase = RuneBase.getRuneBase(rs.getInt("RuneBaseID")); this.runeBase = RuneBase.getRuneBase(rs.getInt("RuneBaseID"));
this.player = rs.getInt("CharacterID"); this.player = rs.getInt("CharacterID");
if (this.runeBase != null) { if (this.runeBase != null) {
this.skillsGranted = SkillReq.getSkillReqsForRune(this.runeBase.getObjectUUID()); this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(this.runeBase.getObjectUUID());
this.powersGranted = PowerReq.getPowerReqsForRune(this.runeBase.getObjectUUID()); this.powersGranted = PowerReq.getPowerReqsForRune(this.runeBase.getObjectUUID());
this.effectsGranted = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE(this.runeBase.getObjectUUID()); this.effectsGranted = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE(this.runeBase.getObjectUUID());
} else { } else {
+3 -3
View File
@@ -296,14 +296,14 @@ public class Corpse extends AbstractWorldObject {
//get weight of item //get weight of item
int weight = item.template.getItemWt(); int weight = item.template.item_wt;
//make sure looter has room for item //make sure looter has room for item
if (item.template.getItemType().equals(ItemType.GOLD) == false && !looterItems.hasRoomInventory(weight)) if (item.template.item_type.equals(ItemType.GOLD) == false && !looterItems.hasRoomInventory(weight))
return null; return null;
//attempt to transfer item in db //attempt to transfer item in db
if (item.template.getItemType().equals(ItemType.GOLD)) { if (item.template.item_type.equals(ItemType.GOLD)) {
if (!looterItems.moveGoldToInventory(item, item.getNumOfItems())) if (!looterItems.moveGoldToInventory(item, item.getNumOfItems()))
return null; return null;
} else if (!item.moveItemToInventory(looter)) } else if (!item.moveItemToInventory(looter))
+3 -3
View File
@@ -22,7 +22,7 @@ import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.UpdateClientAlliancesMsg; import engine.net.client.msg.UpdateClientAlliancesMsg;
import engine.net.client.msg.guild.GuildInfoMsg; import engine.net.client.msg.guild.GuildInfoMsg;
import engine.server.world.WorldServer; import engine.server.world.WorldServer;
import org.joda.time.DateTime; import java.time.Instant;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
@@ -612,8 +612,8 @@ public class Guild extends AbstractWorldObject {
//Add to Guild History //Add to Guild History
if (pc.getGuild() != null) { if (pc.getGuild() != null) {
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(pc.getGuildUUID(), pc, DateTime.now(), historyType)) { if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(pc.getGuildUUID(), pc, Instant.now(), historyType)) {
GuildHistory guildHistory = new GuildHistory(pc.getGuildUUID(), pc.getGuild().name, DateTime.now(), historyType); GuildHistory guildHistory = new GuildHistory(pc.getGuildUUID(), pc.getGuild().name, Instant.now(), historyType);
pc.getGuildHistory().add(guildHistory); pc.getGuildHistory().add(guildHistory);
} }
} }
+8 -7
View File
@@ -13,10 +13,11 @@ package engine.objects;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.mbEnums.GuildHistoryType; import engine.mbEnums.GuildHistoryType;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import org.joda.time.DateTime;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
public class GuildHistory { public class GuildHistory {
@@ -24,12 +25,12 @@ public class GuildHistory {
private int guildID; private int guildID;
private String guildName; private String guildName;
private DateTime time; private Instant time;
private GuildHistoryType historyType; private GuildHistoryType historyType;
public GuildHistory(int guildID, String guildName, public GuildHistory(int guildID, String guildName,
DateTime dateTime, GuildHistoryType historyType) { Instant dateTime, GuildHistoryType historyType) {
super(); super();
this.guildID = guildID; this.guildID = guildID;
this.guildName = guildName; this.guildName = guildName;
@@ -49,9 +50,9 @@ public class GuildHistory {
sqlDateTime = rs.getTimestamp("historyDate"); sqlDateTime = rs.getTimestamp("historyDate");
if (sqlDateTime != null) if (sqlDateTime != null)
this.time = new DateTime(sqlDateTime); this.time = sqlDateTime.toInstant();
else else
this.time = DateTime.now().minusYears(1); this.time = Instant.now().minus(1, ChronoUnit.YEARS);
this.historyType = GuildHistoryType.valueOf(rs.getString("historyType")); this.historyType = GuildHistoryType.valueOf(rs.getString("historyType"));
} }
@@ -77,11 +78,11 @@ public class GuildHistory {
writer.putDateTime(this.time); writer.putDateTime(this.time);
} }
public DateTime getTime() { public Instant getTime() {
return time; return time;
} }
public void setTime(DateTime time) { public void setTime(Instant time) {
this.time = time; this.time = time;
} }
+23 -30
View File
@@ -20,8 +20,6 @@ import engine.net.ByteBufferWriter;
import engine.net.Dispatch; import engine.net.Dispatch;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.DeleteItemMsg; import engine.net.client.msg.DeleteItemMsg;
import engine.parsers.objects.CObjectTemplate;
import engine.parsers.objects.UserPowerAction;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.powers.effectmodifiers.AbstractEffectModifier;
import engine.powers.poweractions.AbstractPowerAction; import engine.powers.poweractions.AbstractPowerAction;
@@ -33,7 +31,6 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
@@ -58,7 +55,7 @@ public class Item extends AbstractWorldObject {
public int templateID; public int templateID;
private long dateToUpgrade; private long dateToUpgrade;
public int magicValue; public int magicValue;
public CObjectTemplate template; public ItemTemplate template;
public String name = ""; public String name = "";
public int prefixToken; // Forge support public int prefixToken; // Forge support
public int suffixToken; // Forge support public int suffixToken; // Forge support
@@ -71,14 +68,14 @@ public class Item extends AbstractWorldObject {
public Item(int templateID) { public Item(int templateID) {
super(); super();
this.templateID = templateID; this.templateID = templateID;
this.template = CObjectTemplate.lookup(templateID); this.template = ItemTemplate.templates.get(templateID);
this.chargesRemaining = this.template.getItemInitialCharges(); this.chargesRemaining = this.template.item_initial_charges;
this.combat_health_current = this.template.getCombatHealthFull(); this.combat_health_current = this.template.combat_health_full;
this.equipSlot = EquipSlotType.NONE; this.equipSlot = EquipSlotType.NONE;
this.containerType = ItemContainerType.NONE; this.containerType = ItemContainerType.NONE;
this.numberOfItems = 1; this.numberOfItems = 1;
this.flags.addAll(this.template.getItemFlags()); this.flags.addAll(this.template.item_flags);
this.value = this.template.getItemValue(); this.value = this.template.item_value;
this.magicValue = this.value + calcMagicValue(); this.magicValue = this.value + calcMagicValue();
loadTemplateEnchantments(); loadTemplateEnchantments();
} }
@@ -90,7 +87,7 @@ public class Item extends AbstractWorldObject {
super(rs); super(rs);
this.templateID = rs.getInt("templateID"); this.templateID = rs.getInt("templateID");
this.template = CObjectTemplate.lookup(this.templateID); this.template = ItemTemplate.templates.get(this.templateID);
if (this.template == null) if (this.template == null)
Logger.error("Null template of " + this.templateID); Logger.error("Null template of " + this.templateID);
@@ -169,7 +166,7 @@ public class Item extends AbstractWorldObject {
this.value = rs.getInt("value"); this.value = rs.getInt("value");
if (this.value == 0) { if (this.value == 0) {
this.value = this.template.getItemValue(); this.value = this.template.item_value;
this.magicValue = this.value + calcMagicValue(); this.magicValue = this.value + calcMagicValue();
} else } else
this.magicValue = this.value; // Value was overridden in vendor inventory this.magicValue = this.value; // Value was overridden in vendor inventory
@@ -241,7 +238,7 @@ public class Item extends AbstractWorldObject {
writer.putString(item.name); // Unknown. pad? writer.putString(item.name); // Unknown. pad?
writer.put((byte) 1); // End Datablock byte writer.put((byte) 1); // End Datablock byte
writer.putFloat(item.template.getCombatHealthFull()); writer.putFloat(item.template.combat_health_full);
writer.putFloat((float) item.combat_health_current); writer.putFloat((float) item.combat_health_current);
writer.put((byte) 1); // End Datablock byte writer.put((byte) 1); // End Datablock byte
@@ -258,7 +255,7 @@ public class Item extends AbstractWorldObject {
} else } else
writer.putInt(item.numberOfItems); // Amount of gold writer.putInt(item.numberOfItems); // Amount of gold
} else } else
writer.putInt(item.template.getItemValue()); writer.putInt(item.template.item_value);
writer.putInt(item.getValue()); writer.putInt(item.getValue());
@@ -291,7 +288,7 @@ public class Item extends AbstractWorldObject {
writer.putInt(36); //Magical, blue name writer.putInt(36); //Magical, blue name
else else
writer.putInt(40); //Magical, unidentified writer.putInt(40); //Magical, unidentified
else if (item.template.getItemUserPowerAction().isEmpty() == false) else if (item.template.item_user_power_action.size() > 0)
writer.putInt(36); //Magical, blue name writer.putInt(36); //Magical, blue name
else else
writer.putInt(4); //Non-Magical, grey name writer.putInt(4); //Non-Magical, grey name
@@ -301,7 +298,7 @@ public class Item extends AbstractWorldObject {
writer.put((byte) 0); writer.put((byte) 0);
if (item.template.getItemType().equals(ItemType.EMPLOYMENTCONTRACT) == false) { if (item.template.item_type.equals(ItemType.EMPLOYMENTCONTRACT) == false) {
writer.putShort((short) 0); writer.putShort((short) 0);
return; return;
} }
@@ -466,7 +463,7 @@ public class Item extends AbstractWorldObject {
int serialized = 0; int serialized = 0;
for (Item item : list) { for (Item item : list) {
if (item.template.getItemType().equals(ItemType.GOLD)) if (item.template.item_type.equals(ItemType.GOLD))
if (item.numberOfItems == 0) if (item.numberOfItems == 0)
continue; continue;
try { try {
@@ -500,7 +497,7 @@ public class Item extends AbstractWorldObject {
int serialized = 0; int serialized = 0;
for (Item item : list) { for (Item item : list) {
if (item.template.getItemType().equals(ItemType.GOLD)) if (item.template.item_type.equals(ItemType.GOLD))
if (item.numberOfItems == 0) if (item.numberOfItems == 0)
continue; continue;
try { try {
@@ -934,16 +931,12 @@ public class Item extends AbstractWorldObject {
private void loadTemplateEnchantments() { private void loadTemplateEnchantments() {
EffectsBase effect; EffectsBase effect;
LinkedHashMap<String, int[]> templateEnchantments = new LinkedHashMap<>();
if (ConfigManager.serverType.equals(mbEnums.ServerType.LOGINSERVER)) if (ConfigManager.serverType.equals(mbEnums.ServerType.LOGINSERVER))
return; return;
// Duplicate powers collapse to the last entry; applying one twice would double its magic value.
for (UserPowerAction userPowerAction : this.template.getItemUserPowerAction())
templateEnchantments.put(userPowerAction.power, userPowerAction.arguments);
for (String effectID : templateEnchantments.keySet()) { for (String effectID : this.template.item_user_power_action.keySet()) {
effect = PowersManager.getEffectByIDString(effectID); effect = PowersManager.getEffectByIDString(effectID);
@@ -953,7 +946,7 @@ public class Item extends AbstractWorldObject {
} }
AbstractPowerAction apa = PowersManager.getPowerActionByIDString(effect.getIDString()); AbstractPowerAction apa = PowersManager.getPowerActionByIDString(effect.getIDString());
apa.applyBakedInStatsForItem(this, templateEnchantments.get(effectID)[0]); apa.applyBakedInStatsForItem(this, this.template.item_user_power_action.get(effectID)[0]);
} }
} }
@@ -962,7 +955,7 @@ public class Item extends AbstractWorldObject {
// No enchantments for negative id items in the db. Early exit. // No enchantments for negative id items in the db. Early exit.
if (this.objectUUID < 0) { if (this.objectUUID < 0) {
this.magicValue = this.template.getItemValue() + calcMagicValue(); this.magicValue = this.template.item_value + calcMagicValue();
return; return;
} }
@@ -978,8 +971,8 @@ public class Item extends AbstractWorldObject {
// Value is overridden the db // Value is overridden the db
if (this.value == this.template.getItemValue()) if (this.value == this.template.item_value)
this.magicValue = this.template.getItemValue() + calcMagicValue(); this.magicValue = this.template.item_value + calcMagicValue();
} }
public void addPermanentEnchantment(String enchantID, int rank) { public void addPermanentEnchantment(String enchantID, int rank) {
@@ -1123,11 +1116,11 @@ public class Item extends AbstractWorldObject {
else else
modifiedValue = this.value; modifiedValue = this.value;
if (this.template.getItemInitialCharges() > 0) if (this.template.item_initial_charges > 0)
modifiedValue = modifiedValue * (this.chargesRemaining / this.template.getItemInitialCharges()); modifiedValue = modifiedValue * (this.chargesRemaining / this.template.item_initial_charges);
if (this.template.getCombatHealthFull() > 0) if (this.template.combat_health_full > 0)
modifiedValue = (int) (modifiedValue * (this.combat_health_current / this.template.getCombatHealthFull())); modifiedValue = (int) (modifiedValue * (this.combat_health_current / this.template.combat_health_full));
return modifiedValue; return modifiedValue;
} }
+623
View File
@@ -0,0 +1,623 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.objects;
import engine.math.Vector3fImmutable;
import engine.mbEnums;
import org.json.JSONArray;
import org.json.JSONObject;
import org.pmw.tinylog.Logger;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
public class ItemTemplate {
// MB Dev Notes:
// This class parses JSON data generated by mbEditor Pro 2.1.
// Cache definitions are loaded for ItemType.ITEM, ItemType,DEED
// and ItemType.RUNE.
//
// Exported JSON data is stored in db table static_item_templates
// and can be easily mass updated using tooling available on the Wiki.
//
// Always read never write!
// Use copies of fields to avoid side effects.
// Global template lookup
public static HashMap<Integer, ItemTemplate> templates = new HashMap<>();
public int template_id;
// Template Properties
public String obj_name;
public boolean obj_pickable;
public Vector3fImmutable obj_scale;
public Vector3fImmutable obj_forward_vector;
public Vector3fImmutable obj_default_alignment;
public int obj_render_object;
public int obj_icon;
public final HashMap<String, String> obj_sparse_data = new HashMap<>();
public float combat_health_current;
public float combat_health_full;
public final HashMap<String, Float> combat_attack_resist = new HashMap<>();
public mbEnums.ItemType item_type;
public int item_eq_slots_value;
public boolean item_eq_slots_type;
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_or = EnumSet.noneOf(mbEnums.EquipSlotType.class);
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_and = EnumSet.noneOf(mbEnums.EquipSlotType.class);
public boolean item_takeable;
public int item_value;
public int item_wt;
public float item_passive_defense_mod;
public String item_base_name;
public String item_dsc;
public int item_render_object_female;
public float item_health_full;
public String item_skill_used = "";
public String item_skill_mastery_used = "";
public int item_parry_anim_id;
public float item_bulk_factor;
public final HashMap<mbEnums.ShrineType, Integer> item_offering_info = new HashMap<>();
public int item_defense_rating;
public float item_weapon_wepspeed;
public float item_weapon_max_range;
public int item_weapon_projectile_id;
public float item_weapon_projectile_speed;
public int item_weapon_combat_idle_anim;
public final HashMap<mbEnums.DamageType, int[]> item_weapon_damage = new HashMap<>();
public final ArrayList<int[]> weapon_attack_anim_right = new ArrayList<>();
public final ArrayList<int[]> weapon_attack_anim_left = new ArrayList<>();
public mbEnums.AttributeType item_primary_attr = mbEnums.AttributeType.None;
public mbEnums.AttributeType item_secondary_attr = mbEnums.AttributeType.None;
public final EnumSet<mbEnums.ItemFlags> item_flags = EnumSet.noneOf(mbEnums.ItemFlags.class);
public final EnumSet<mbEnums.ItemUseFlags> item_use_flags = EnumSet.noneOf(mbEnums.ItemUseFlags.class);
public int item_initial_charges;
public final HashMap<String, Integer> item_skill_required = new HashMap<>();
public final EnumSet<mbEnums.MonsterType> item_race_req = EnumSet.noneOf(mbEnums.MonsterType.class);
public final EnumSet<mbEnums.MonsterType> item_race_res = EnumSet.noneOf(mbEnums.MonsterType.class);
public final EnumSet<mbEnums.ClassType> item_class_req = EnumSet.noneOf(mbEnums.ClassType.class);
public final EnumSet<mbEnums.ClassType> item_class_res = EnumSet.noneOf(mbEnums.ClassType.class);
public final EnumSet<mbEnums.DisciplineType> item_disc_req = EnumSet.noneOf(mbEnums.DisciplineType.class);
public final EnumSet<mbEnums.DisciplineType> item_disc_res = EnumSet.noneOf(mbEnums.DisciplineType.class);
public int item_level_req;
public mbEnums.SexType item_sex_req;
public final HashMap<String, int[]> item_user_power_action = new HashMap<>();
public final HashMap<String, Integer> item_power_grant = new HashMap<>();
public final HashMap<String, int[]> item_power_action = new HashMap<>();
public final HashMap<mbEnums.ResourceType, Integer> item_resource_cost = new HashMap<>();
public int modTable;
public int deed_type;
public int deed_furniture_id;
public int deed_target_id;
public int deed_employment;
public int deed_start_rank;
public int deed_name_lookup;
public boolean deed_indoors;
public boolean deed_is_fortress;
public float deed_namelookup_val;
public boolean deed_custom_city;
public int deed_structure_id;
public final HashMap<mbEnums.AttributeType, Integer> rune_attr_adj = new HashMap<>();
public final HashMap<mbEnums.AttributeType, Integer> rune_max_attr_adj = new HashMap<>();
public final HashMap<String, Integer> rune_skill_grant = new HashMap<>();
public final HashMap<String, Integer> skill_granted_skills = new HashMap<>();
public final HashMap<String, Integer> power_granted_skills = new HashMap<>();
public String rune_type;
public String rune_sub_type;
public boolean rune_is_standard_character_creation = false;
public int rune_creation_cost;
public int rune_rank;
public int rune_pracs_per_level;
public float rune_exp_req_to_level;
public mbEnums.SexType rune_sex;
public int rune_class_icon;
public int rune_health;
public int rune_mana;
public int rune_stamina;
public float rune_min_damage;
public float rune_max_damage;
public int rune_attack;
public int rune_defense;
public int rune_level;
public final HashMap<mbEnums.MovementType, Float> rune_speed = new HashMap<>();
public int rune_group_type;
public boolean rune_group_is_faction = false;
public boolean rune_group_is_guild = false;
public String rune_dsc;
public String rune_fx_txt;
public final EnumSet<mbEnums.MobBehaviourType> rune_group_tactics = EnumSet.noneOf(mbEnums.MobBehaviourType.class);
public final EnumSet<mbEnums.MobBehaviourType> rune_group_role_set = EnumSet.noneOf(mbEnums.MobBehaviourType.class);
public boolean rune_renderable = false;
public int rune_natural_power_attack;
public final HashMap<String, String> rune_sparse_data = new HashMap<>();
public final HashMap<String, int[]> rune_skill_adj = new HashMap<>();
public final EnumSet<mbEnums.MonsterType> rune_enemy_monster_types = EnumSet.noneOf(mbEnums.MonsterType.class);
public final EnumSet<mbEnums.MonsterType> rune_not_enemy_monster_types = EnumSet.noneOf(mbEnums.MonsterType.class);
public final ArrayList<Integer> rune_groupee_monster_types = new ArrayList<>();
public final ArrayList<Integer> rune_helper_monster_types = new ArrayList<>();
public int item_bane_rank;
public ItemTemplate(JSONObject jsonObject) {
try {
// Reading a String
obj_name = jsonObject.getString("obj_name");
// Reading a boolean
obj_pickable = jsonObject.getBoolean("obj_pickable");
// Reading floats from an array (note always check for empty arrays)
JSONArray scaleData = jsonObject.getJSONArray("obj_scale");
if (scaleData.isEmpty() == false)
obj_scale = new Vector3fImmutable(scaleData.getFloat(0), scaleData.getFloat(1),
scaleData.getFloat(2));
JSONArray forwardVector = jsonObject.getJSONArray("obj_forward_vector");
if (forwardVector.isEmpty() == false)
obj_forward_vector = new Vector3fImmutable(forwardVector.getFloat(0), forwardVector.getFloat(1),
forwardVector.getFloat(2));
JSONArray defaultAlignment = jsonObject.getJSONArray("obj_default_alignment");
if (defaultAlignment.isEmpty() == false)
obj_default_alignment = new Vector3fImmutable(defaultAlignment.getFloat(0), defaultAlignment.getFloat(1),
defaultAlignment.getFloat(2));
// Reading an integer value
obj_render_object = jsonObject.getInt("obj_render_object");
obj_icon = jsonObject.getInt("obj_icon");
JSONObject obj_sparse_json = jsonObject.getJSONObject("obj_sparse_data");
for (String sparseType : obj_sparse_json.keySet()) {
Object sparseValue = obj_sparse_json.get(sparseType);
obj_sparse_data.put(sparseType, sparseValue.toString());
}
// Banes are defined by their sparse data field
if (obj_sparse_data.get("ACTIONRESPONSE") != null)
if (obj_sparse_data.get("ACTIONRESPONSE").equals("4250517122"))
item_bane_rank = jsonObject.getInt("item_bane_rank");
// Reading float values
combat_health_current = jsonObject.getFloat("combat_health_current");
combat_health_full = jsonObject.getFloat("combat_health_full");
// Reading a hashmap of floats
JSONObject resist_json = jsonObject.getJSONObject("combat_attack_resist");
for (String resistType : resist_json.keySet()) {
float resistValue = resist_json.getFloat(resistType);
combat_attack_resist.put(resistType, resistValue);
}
// Parsing an enum
item_type = mbEnums.ItemType.valueOf(jsonObject.getString("item_type"));
item_eq_slots_value = jsonObject.getInt("item_eq_slots_value");
item_eq_slots_type = jsonObject.getBoolean("item_eq_slots_type");
// Parsing an enumset
JSONArray eq_slots_or = jsonObject.getJSONArray("item_eq_slots_or");
if (eq_slots_or.isEmpty() == false)
for (Object o : eq_slots_or)
item_eq_slots_or.add(mbEnums.EquipSlotType.valueOf((String) o));
JSONArray eq_slots_and = jsonObject.getJSONArray("item_eq_slots_and");
if (eq_slots_and.isEmpty() == false)
for (Object o : eq_slots_and)
item_eq_slots_and.add(mbEnums.EquipSlotType.valueOf((String) o));
item_takeable = jsonObject.getBoolean("item_takeable");
item_value = (jsonObject.getInt("item_value"));
item_wt = jsonObject.getInt("item_wt");
item_passive_defense_mod = jsonObject.getFloat("item_passive_defense_mod");
item_base_name = jsonObject.getString("item_base_name");
item_dsc = jsonObject.getString("item_dsc");
item_render_object_female = jsonObject.getInt("item_render_object_female");
item_health_full = jsonObject.getFloat("item_health_full");
Object skill_used = jsonObject.get("item_skill_used");
if (skill_used instanceof String) {
if (skill_used.equals("Cloth") == false)
item_skill_used = (String) skill_used;
}
Object mastery_used = jsonObject.get("item_skill_mastery_used");
if (mastery_used instanceof String)
item_skill_mastery_used = (String) mastery_used;
item_parry_anim_id = jsonObject.getInt("item_parry_anim_id");
// Reading offering data
JSONArray offering_data = jsonObject.getJSONArray("item_offering_info");
for (Object entry : offering_data) {
JSONObject offering_entry = (JSONObject) entry;
String offering_type = offering_entry.getString("offering_type").replaceAll("-", "");
int offering_value = offering_entry.getInt("offering_value");
item_offering_info.put(mbEnums.ShrineType.valueOf(offering_type), offering_value);
}
// Fields only present for ARMOR
if (item_type.equals(mbEnums.ItemType.ARMOR)) {
item_bulk_factor = jsonObject.getFloat("item_bulk_factor");
item_defense_rating = jsonObject.getInt("item_defense_rating");
}
// Fields only present for WEAPON
if (item_type.equals(mbEnums.ItemType.WEAPON)) {
JSONObject item_weapon = jsonObject.getJSONObject("item_weapon");
item_weapon_wepspeed = item_weapon.getFloat("weapon_wepspeed");
item_weapon_max_range = item_weapon.getFloat("weapon_max_range");
item_weapon_projectile_id = item_weapon.getInt("weapon_projectile_id");
item_weapon_projectile_speed = item_weapon.getFloat("weapon_projectile_speed");
item_weapon_combat_idle_anim = item_weapon.getInt("weapon_combat_idle_anim");
JSONArray weapon_damage = item_weapon.getJSONArray("weapon_damage");
if (weapon_damage.isEmpty() == false)
for (Object o : weapon_damage) {
JSONObject damage_entry = (JSONObject) o;
mbEnums.DamageType damageType = mbEnums.DamageType.getDamageType(damage_entry.getString("damage_type"));
int min = damage_entry.getInt("damage_min");
int max = damage_entry.getInt("damage_max");
int[] minMax = {min, max};
item_weapon_damage.put(damageType, minMax);
}
JSONArray attack_anim_right = item_weapon.getJSONArray("weapon_attack_anim_right");
if (attack_anim_right.isEmpty() == false)
for (Object o : attack_anim_right) {
JSONArray animationEntry = (JSONArray) o;
int animation = animationEntry.getInt(0);
int duration = animationEntry.getInt(1);
weapon_attack_anim_right.add(new int[]{animation, duration});
}
JSONArray attack_anim_left = item_weapon.getJSONArray("weapon_attack_anim_left");
if (attack_anim_left.isEmpty() == false)
for (Object o : attack_anim_left) {
JSONArray animationEntry = (JSONArray) o;
int animation = animationEntry.getInt(0);
int duration = animationEntry.getInt(1);
weapon_attack_anim_left.add(new int[]{animation, duration});
}
item_primary_attr = mbEnums.AttributeType.valueOf(jsonObject.getString("item_primary_attr"));
item_secondary_attr = mbEnums.AttributeType.valueOf(jsonObject.getString("item_secondary_attr"));
}
JSONArray itemflags = jsonObject.getJSONArray("item_flags");
if (itemflags.isEmpty() == false)
for (Object o : itemflags) {
String flag = (String) o;
if (flag.equals("None") == false)
item_flags.add(mbEnums.ItemFlags.valueOf((String) o));
}
JSONArray itemUseflags = jsonObject.getJSONArray("item_use_flags");
if (itemUseflags.isEmpty() == false)
for (Object o : itemUseflags)
item_use_flags.add(mbEnums.ItemUseFlags.valueOf((String) o));
item_initial_charges = jsonObject.getInt("item_initial_charges");
JSONArray skill_required = jsonObject.getJSONArray("item_skill_req");
if (skill_required.isEmpty() == false)
for (Object o : skill_required) {
JSONObject skill_req = (JSONObject) o;
String skill_type = skill_req.getString("skill_type");
int skill_level = skill_req.getInt("skill_level");
if (skill_type.equals("Cloth") == false)
item_skill_required.put(skill_type, skill_level);
}
JSONObject race_required = jsonObject.getJSONObject("item_race_req");
boolean restrict = race_required.getBoolean("restrict");
JSONArray races = race_required.getJSONArray("races");
if (races.isEmpty() == false)
for (Object o : races) {
String race = (String) o;
race = race.replaceAll("\\s", "");
race = race.replaceAll(",", "");
race = race.replaceAll("-", "");
if (restrict)
item_race_res.add(mbEnums.MonsterType.valueOf(race));
else
item_race_req.add(mbEnums.MonsterType.valueOf(race));
}
JSONObject class_required = jsonObject.getJSONObject("item_class_req");
restrict = class_required.getBoolean("restrict");
JSONArray classes = class_required.getJSONArray("classes");
if (classes.isEmpty() == false)
for (Object o : classes) {
String classEntry = (String) o;
classEntry = classEntry.replaceAll("\\s", "");
classEntry = classEntry.replaceAll(",", "");
if (restrict)
item_class_res.add(mbEnums.ClassType.valueOf(classEntry));
else
item_class_req.add(mbEnums.ClassType.valueOf(classEntry));
}
JSONObject disc_required = jsonObject.getJSONObject("item_disc_req");
restrict = disc_required.getBoolean("restrict");
JSONArray discs = disc_required.getJSONArray("discs");
if (discs.isEmpty() == false)
for (Object o : discs) {
String disc = (String) o;
disc = disc.replaceAll("\\s", "");
disc = disc.replaceAll(",", "");
if (restrict)
item_disc_res.add(mbEnums.DisciplineType.valueOf(disc));
else
item_disc_req.add(mbEnums.DisciplineType.valueOf(disc));
}
item_level_req = jsonObject.getInt("item_level_req");
item_sex_req = mbEnums.SexType.valueOf(jsonObject.getString("item_sex_req"));
JSONArray userPowerActions = jsonObject.getJSONArray("item_user_power_action");
if (userPowerActions.isEmpty() == false)
for (Object o : userPowerActions) {
JSONObject powerActionEntry = (JSONObject) o;
String power = powerActionEntry.getString("power");
JSONArray args = powerActionEntry.getJSONArray("arguments");
int[] arguments = {args.getInt(0), args.getInt(1)};
item_user_power_action.put(power, arguments);
}
JSONArray powerGrantsArray = jsonObject.getJSONArray("item_power_grant");
if (powerGrantsArray.isEmpty() == false) {
for (Object grantArrayEntry : powerGrantsArray) {
JSONObject powerGrantEntry = (JSONObject) grantArrayEntry;
String power_type = powerGrantEntry.getString("power_type");
int power_value = powerGrantEntry.getInt("power_value");
item_power_grant.put(power_type, power_value);
JSONArray skill_granted_array = powerGrantEntry.getJSONArray("power_granted_skills");
for (Object skillGrantEntry : skill_granted_array) {
JSONArray skill_entry = (JSONArray) skillGrantEntry;
String skill_type = skill_entry.getString(0);
int skill_level = skill_entry.getInt(1);
power_granted_skills.put(skill_type, skill_level);
}
}
}
JSONArray item_power_actions = jsonObject.getJSONArray("item_power_action");
if (item_power_actions.isEmpty() == false)
for (Object o : item_power_actions) {
JSONObject powerActionEntry = (JSONObject) o;
String power = powerActionEntry.getString("power_type");
JSONArray power_actions = powerActionEntry.getJSONArray("power_actions");
JSONObject argument_entry = power_actions.getJSONObject(0);
JSONArray power_args = argument_entry.getJSONArray("power_arguments");
int[] power_arguments = {power_args.getInt(0), power_args.getInt(1)};
item_power_action.put(power, power_arguments);
}
JSONArray resource_costs = jsonObject.getJSONArray("item_resource_costs");
if (resource_costs.isEmpty() == false)
for (Object o : resource_costs) {
JSONObject resource_entry = (JSONObject) o;
mbEnums.ResourceType resource_type = mbEnums.ResourceType.valueOf(resource_entry.getString("resource_type").toUpperCase());
int resource_value = resource_entry.getInt("resource_value");
item_resource_cost.put(resource_type, resource_value);
}
// Deed related fields
if (item_type.equals(mbEnums.ItemType.DEED)) {
deed_type = jsonObject.getInt("deed_type");
deed_furniture_id = jsonObject.getInt("deed_furniture_id");
deed_target_id = jsonObject.getInt("deed_target_id");
deed_employment = jsonObject.getInt("deed_employment");
deed_start_rank = jsonObject.getInt("deed_start_rank");
deed_name_lookup = jsonObject.getInt("deed_name_lookup");
deed_indoors = jsonObject.getBoolean("deed_indoors");
deed_is_fortress = jsonObject.getBoolean("deed_is_fortress");
deed_namelookup_val = jsonObject.getFloat("deed_namelookup_val");
deed_custom_city = jsonObject.getBoolean("deed_custom_city");
deed_structure_id = jsonObject.getInt("deed_structure_id");
}
if (item_type.equals(mbEnums.ItemType.RUNE)) {
rune_type = jsonObject.getString("rune_type");
Object subType = jsonObject.get("rune_sub_type");
if (subType instanceof String)
rune_sub_type = (String) subType;
rune_is_standard_character_creation = jsonObject.getBoolean("rune_is_standard_character_creation");
rune_creation_cost = jsonObject.getInt("rune_creation_cost");
rune_rank = jsonObject.getInt("rune_rank");
rune_pracs_per_level = jsonObject.getInt("rune_pracs_per_level");
rune_exp_req_to_level = jsonObject.getFloat("rune_exp_req_to_level");
rune_sex = mbEnums.SexType.valueOf(jsonObject.getString("rune_sex"));
rune_class_icon = jsonObject.getInt("rune_class_icon");
rune_health = jsonObject.getInt("rune_health");
rune_mana = jsonObject.getInt("rune_mana");
rune_stamina = jsonObject.getInt("rune_stamina");
rune_min_damage = jsonObject.getFloat("rune_min_damage");
rune_max_damage = jsonObject.getFloat("rune_max_damage");
rune_attack = jsonObject.getInt("rune_attack");
rune_defense = jsonObject.getInt("rune_defense");
rune_level = jsonObject.getInt("rune_level");
JSONObject rune_speed_json = jsonObject.getJSONObject("rune_speed");
for (String key : rune_speed_json.keySet()) {
mbEnums.MovementType movementType = mbEnums.MovementType.valueOf(key);
float speed = rune_speed_json.getFloat(key);
rune_speed.put(movementType, speed);
}
JSONObject rune_group = jsonObject.getJSONObject("rune_group");
rune_group_type = rune_group.getInt("group_type");
rune_group_is_faction = rune_group.getBoolean("group_is_faction");
rune_group_is_guild = rune_group.getBoolean("group_is_guild");
rune_dsc = jsonObject.getString("rune_dsc");
rune_fx_txt = jsonObject.getString("rune_fx_txt");
long group_tactics_bitvector = jsonObject.getLong("rune_group_tactics");
rune_group_tactics.addAll(mbEnums.fromLong(group_tactics_bitvector, mbEnums.MobBehaviourType.class));
long group_role_bitvector = jsonObject.getLong("rune_group_role_set");
rune_group_role_set.addAll(mbEnums.fromLong(group_role_bitvector, mbEnums.MobBehaviourType.class));
JSONArray enemy_types_json = jsonObject.getJSONArray("rune_enemy_monster_types");
for (Object o : enemy_types_json) {
String enemy = (String) o;
enemy = enemy.replaceAll("-", "");
mbEnums.MonsterType monsterType = mbEnums.MonsterType.valueOf(enemy);
rune_enemy_monster_types.add(monsterType);
}
JSONArray not_enemy_types_json = jsonObject.getJSONArray("rune_not_enemy_monster_types");
for (Object o : not_enemy_types_json) {
String notenemy = (String) o;
notenemy = notenemy.replaceAll("-", "");
mbEnums.MonsterType monsterType = mbEnums.MonsterType.valueOf(notenemy);
rune_not_enemy_monster_types.add(monsterType);
}
JSONArray groupee_types_json = jsonObject.getJSONArray("rune_groupee_monster_types");
for (Object o : groupee_types_json) {
int groupeeId = (int) o;
rune_groupee_monster_types.add(groupeeId);
}
JSONArray helper_types_json = jsonObject.getJSONArray("rune_helper_monster_types");
for (Object o : helper_types_json) {
int helperId = (int) o;
rune_helper_monster_types.add(helperId);
}
rune_renderable = jsonObject.getBoolean("rune_renderable");
rune_natural_power_attack = jsonObject.getInt("rune_natural_power_attack");
JSONObject rune_sparse_json = jsonObject.getJSONObject("rune_sparse_data");
for (String sparseType : rune_sparse_json.keySet()) {
Object sparseValue = rune_sparse_json.get(sparseType);
rune_sparse_data.put(sparseType, sparseValue.toString());
}
JSONArray skill_adj_json = (JSONArray) jsonObject.get("rune_skill_adj");
for (Object skillEntry : skill_adj_json) {
JSONObject skill = (JSONObject) skillEntry;
String typeString = skill.getString("skill_type");
JSONArray adjArray = skill.getJSONArray("skill_adjusts");
for (Object adjustList : adjArray) {
JSONArray adjustEntry = (JSONArray) adjustList;
int[] adjust = {adjustEntry.getInt(0), adjustEntry.getInt(1)};
rune_skill_adj.put(typeString, adjust);
}
}
JSONArray attr_adj_json = jsonObject.getJSONArray("rune_attr_adj");
for (Object attributeEntry : attr_adj_json) {
JSONObject attribute = (JSONObject) attributeEntry;
String typeString = attribute.getString("attr_type");
mbEnums.AttributeType attributeType = mbEnums.AttributeType.valueOf(typeString);
int attributeValue = attribute.getInt("attr_value");
rune_attr_adj.put(attributeType, attributeValue);
}
JSONArray max_attr_adj_json = jsonObject.getJSONArray("rune_max_attr_adj");
for (Object attributeEntry : max_attr_adj_json) {
JSONObject attribute = (JSONObject) attributeEntry;
String typeString = attribute.getString("attr_type");
mbEnums.AttributeType attributeType = mbEnums.AttributeType.valueOf(typeString);
int attributeValue = attribute.getInt("attr_value");
rune_max_attr_adj.put(attributeType, attributeValue);
}
JSONArray skill_grant_json = jsonObject.getJSONArray("rune_skill_grant");
if (skill_grant_json.isEmpty() == false)
for (Object runeSkillEntry : skill_grant_json) {
JSONObject skill_granted = (JSONObject) runeSkillEntry;
String typeString = skill_granted.getString("skill_type");
int skill_level = skill_granted.getInt("skill_value");
rune_skill_grant.put(typeString, skill_level);
JSONArray skill_granted_array = skill_granted.getJSONArray("skill_granted_skills");
for (Object skillGrantEntry : skill_granted_array) {
JSONArray skill_entry = (JSONArray) skillGrantEntry;
typeString = skill_entry.getString(0);
skill_level = skill_entry.getInt(1);
skill_granted_skills.put(typeString, skill_level);
}
}
}
} catch (Exception e) {
Logger.error(obj_name + ":" + e);
}
}
}
-29
View File
@@ -9,16 +9,10 @@
package engine.objects; package engine.objects;
import engine.mbEnums;
import engine.parsers.objects.RuneTemplate;
import engine.util.Hasher;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
public class MaxSkills { public class MaxSkills {
@@ -48,29 +42,6 @@ public class MaxSkills {
this.maxSkillPercent = maxSkillPercent; this.maxSkillPercent = maxSkillPercent;
} }
public static void LoadAllMaxSkills() {
ArrayList<MaxSkills> maxSkillsList;
int entryCount = 0;
// Talents only: class/discipline/race adjusts are skill grants, and contracts that key on those runes would read them as caps
for (RuneTemplate rune : RuneTemplate._runes.values()) {
if (rune.rune_type != mbEnums.RuneType.TALENT || rune.rune_skill_adj.isEmpty())
continue;
maxSkillsList = new ArrayList<>();
for (Map.Entry<String, ArrayList<int[]>> skillAdjust : rune.rune_skill_adj.entrySet())
for (int[] adjust : skillAdjust.getValue())
maxSkillsList.add(new MaxSkills(rune.template_id, Hasher.SBStringHash(skillAdjust.getKey()), adjust[1], adjust[0]));
MaxSkillsSet.put(rune.template_id, maxSkillsList);
entryCount += maxSkillsList.size();
}
Logger.info("Loaded " + entryCount + " max skills for " + MaxSkillsSet.size() + " runes");
}
public int getRuneID() { public int getRuneID() {
return runeID; return runeID;
} }
+11 -45
View File
@@ -24,7 +24,8 @@ import engine.net.client.msg.PetMsg;
import engine.net.client.msg.PlaceAssetMsg; import engine.net.client.msg.PlaceAssetMsg;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.joda.time.DateTime; import java.time.LocalDateTime;
import java.time.ZoneId;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
@@ -71,7 +72,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
public long nextAttackTime = System.currentTimeMillis(); public long nextAttackTime = System.currentTimeMillis();
private int lastMobPowerToken = 0; private int lastMobPowerToken = 0;
private DeferredPowerJob weaponPower; private DeferredPowerJob weaponPower;
private DateTime upgradeDateTime = null; private LocalDateTime upgradeDateTime = null;
private boolean lootSync = false; private boolean lootSync = false;
// New Mobile constructor. Fill in the blanks and then call // New Mobile constructor. Fill in the blanks and then call
@@ -126,7 +127,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
sqlDateTime = rs.getTimestamp("upgradeDate"); sqlDateTime = rs.getTimestamp("upgradeDate");
if (sqlDateTime != null) if (sqlDateTime != null)
upgradeDateTime = new DateTime(sqlDateTime); upgradeDateTime = LocalDateTime.ofInstant(sqlDateTime.toInstant(), ZoneId.systemDefault());
else else
upgradeDateTime = null; upgradeDateTime = null;
@@ -436,30 +437,6 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
return mobile; return mobile;
} }
// MB_MINION_SPAWN_TIME (seconds) shortens guard/siege minion spawns for testing; 0 or blank keeps the normal timers.
private static int minionSpawnDelay(int defaultDelay) {
String overrideValue;
int overrideDelay;
overrideValue = ConfigManager.MB_MINION_SPAWN_TIME.getValue();
if (overrideValue == null || overrideValue.trim().isEmpty())
return defaultDelay;
try {
overrideDelay = Integer.parseInt(overrideValue.trim());
} catch (NumberFormatException e) {
Logger.warn("MB_MINION_SPAWN_TIME is not a number: " + overrideValue);
return defaultDelay;
}
if (overrideDelay <= 0)
return defaultDelay;
return overrideDelay;
}
public static synchronized Mob createGuardMinion(Mob guardCaptain, short level, String minionName) { public static synchronized Mob createGuardMinion(Mob guardCaptain, short level, String minionName) {
Mob minionMobile; Mob minionMobile;
@@ -479,7 +456,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
minionMobile.deathTime = System.currentTimeMillis(); minionMobile.deathTime = System.currentTimeMillis();
minionMobile.guardCaptain = guardCaptain; minionMobile.guardCaptain = guardCaptain;
minionMobile.spawnDelay = minionSpawnDelay((int) (-2.500 * guardCaptain.building.getRank() + 22.5) * 60); minionMobile.spawnDelay = (int) (-2.500 * guardCaptain.building.getRank() + 22.5) * 60;
minionMobile.behaviourType = mbEnums.MobBehaviourType.GuardMinion; minionMobile.behaviourType = mbEnums.MobBehaviourType.GuardMinion;
minionMobile.agentType = AIAgentType.GUARDMINION; minionMobile.agentType = AIAgentType.GUARDMINION;
minionMobile.guardedCity = guardCaptain.guardedCity; minionMobile.guardedCity = guardCaptain.guardedCity;
@@ -538,7 +515,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
siegeMinion.behaviourType = MobBehaviourType.SiegeEngine; siegeMinion.behaviourType = MobBehaviourType.SiegeEngine;
siegeMinion.agentType = AIAgentType.SIEGEENGINE; siegeMinion.agentType = AIAgentType.SIEGEENGINE;
siegeMinion.bindLoc = Vector3fImmutable.ZERO; siegeMinion.bindLoc = Vector3fImmutable.ZERO;
siegeMinion.spawnDelay = minionSpawnDelay(60 * 15); siegeMinion.spawnDelay = (60 * 15);
siegeMinion.runAfterLoad(); siegeMinion.runAfterLoad();
@@ -576,12 +553,6 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
petMinion.despawned = false; petMinion.despawned = false;
petMinion.runAfterLoad(); petMinion.runAfterLoad();
// Summoned pets carry MASK_PET. Necro pets keep their own NecroPet handling.
if (!petMinion.isNecroPet())
petMinion.setObjectTypeMask(petMinion.getObjectTypeMask() | MBServerStatics.MASK_PET);
DbManager.addToCache(petMinion); DbManager.addToCache(petMinion);
petMinion.setLoc(petMinion.bindLoc); petMinion.setLoc(petMinion.bindLoc);
@@ -623,8 +594,8 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
// Submit upgrade job for future date or current instant // Submit upgrade job for future date or current instant
if (mob.getUpgradeDateTime().isAfter(DateTime.now())) if (mob.getUpgradeDateTime().isAfter(LocalDateTime.now()))
JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(mob), mob.getUpgradeDateTime().getMillis()); JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(mob), mob.getUpgradeDateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
else else
JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(mob), 0); JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(mob), 0);
@@ -650,7 +621,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
return upgradeCost; return upgradeCost;
} }
public static void setUpgradeDateTime(Mob mob, DateTime upgradeDateTime) { public static void setUpgradeDateTime(Mob mob, LocalDateTime upgradeDateTime) {
if (!DbManager.MobQueries.updateUpgradeTime(mob, upgradeDateTime)) { if (!DbManager.MobQueries.updateUpgradeTime(mob, upgradeDateTime)) {
Logger.error("Failed to set upgradeTime for building " + mob.currentID); Logger.error("Failed to set upgradeTime for building " + mob.currentID);
@@ -1348,11 +1319,6 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
if (!ac.getObjectType().equals(GameObjectType.PlayerCharacter)) if (!ac.getObjectType().equals(GameObjectType.PlayerCharacter))
return; return;
// siege engines only switch targets on damage, see AbstractCharacter.modifyHealth
if (this.isSiege())
return;
if (this.getCombatTarget() == null) if (this.getCombatTarget() == null)
this.setCombatTarget(ac); this.setCombatTarget(ac);
@@ -1388,7 +1354,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
this.weaponPower = weaponPower; this.weaponPower = weaponPower;
} }
public DateTime getUpgradeDateTime() { public LocalDateTime getUpgradeDateTime() {
lock.readLock().lock(); lock.readLock().lock();
@@ -1468,7 +1434,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
if (!building.transferGold(-rankCost, false)) if (!building.transferGold(-rankCost, false))
return; return;
DateTime dateToUpgrade = DateTime.now().plusHours(Mob.getUpgradeTime(this)); LocalDateTime dateToUpgrade = LocalDateTime.now().plusHours(Mob.getUpgradeTime(this));
Mob.setUpgradeDateTime(this, dateToUpgrade); Mob.setUpgradeDateTime(this, dateToUpgrade);
// Schedule upgrade job // Schedule upgrade job
+1 -5
View File
@@ -127,13 +127,9 @@ public class MobBase extends AbstractGameObject {
for (BootySetEntry equipmentSetEntry : equipList) { for (BootySetEntry equipmentSetEntry : equipList) {
Item item = new Item(equipmentSetEntry.templateID); Item item = new Item(equipmentSetEntry.templateID);
if (item.template.getItemEqSlotsOr().isEmpty())
continue;
item.objectUUID = ItemManager.lastNegativeID.decrementAndGet(); item.objectUUID = ItemManager.lastNegativeID.decrementAndGet();
item.drop_chance = equipmentSetEntry.dropChance; item.drop_chance = equipmentSetEntry.dropChance;
item.equipSlot = item.template.getItemEqSlotsOr().iterator().next(); item.equipSlot = item.template.item_eq_slots_or.iterator().next();
equip.put(item.equipSlot, item); equip.put(item.equipSlot, item);
} }
-57
View File
@@ -9,23 +9,12 @@
package engine.objects; package engine.objects;
import engine.parsers.objects.RuneTemplate;
import engine.parsers.objects.UserPowerAction;
import engine.parsers.objects.wpak.PowerActionTemplate;
import engine.server.MBServerStatics;
import engine.util.Hasher;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;
public class MobBaseEffects { public class MobBaseEffects {
private static final ConcurrentHashMap<Integer, ArrayList<MobBaseEffects>> effectsByRune = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
private int mobBaseID; private int mobBaseID;
private int token; private int token;
private int rank; private int rank;
@@ -41,52 +30,6 @@ public class MobBaseEffects {
this.reqLvl = rs.getInt("reqLvl"); this.reqLvl = rs.getInt("reqLvl");
} }
public MobBaseEffects(int token, int rank, int reqLvl) {
this.token = token;
this.rank = rank;
this.reqLvl = reqLvl;
}
public static ArrayList<MobBaseEffects> getEffectsForRune(int runeID) {
return effectsByRune.computeIfAbsent(runeID, MobBaseEffects::loadEffectsForRune);
}
// item_user_power_action entries are {action id, [rank, reqLvl]}; the action names the effect to apply
private static ArrayList<MobBaseEffects> loadEffectsForRune(int runeID) {
ArrayList<MobBaseEffects> runeEffects = new ArrayList<>();
HashSet<String> seenEntries = new HashSet<>();
RuneTemplate rune = RuneTemplate._runes.get(runeID);
PowerActionTemplate powerAction;
String effectID;
int rank;
int reqLvl;
if (rune == null)
return runeEffects;
for (UserPowerAction userPowerAction : rune.item_user_power_action) {
rank = userPowerAction.arguments.length > 0 ? userPowerAction.arguments[0] : 0;
reqLvl = userPowerAction.arguments.length > 1 ? userPowerAction.arguments[1] : 0;
// 54 rune files repeat their whole list; the DB kept each entry once
if (!seenEntries.add(userPowerAction.power + ":" + rank + ":" + reqLvl))
continue;
powerAction = PowerActionTemplate._powerActions.get(userPowerAction.power);
if (powerAction != null && !powerAction.effect_ids.isEmpty())
effectID = powerAction.effect_ids.get(0);
else
effectID = userPowerAction.power;
runeEffects.add(new MobBaseEffects(Hasher.SBStringHash(effectID), rank, reqLvl));
}
return runeEffects;
}
/** /**
* @return the mobBaseID * @return the mobBaseID
+6 -7
View File
@@ -15,7 +15,6 @@ import engine.gameManager.PowersManager;
import engine.mbEnums; import engine.mbEnums;
import engine.mbEnums.ItemType; import engine.mbEnums.ItemType;
import engine.mbEnums.OwnerType; import engine.mbEnums.OwnerType;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.poweractions.AbstractPowerAction; import engine.powers.poweractions.AbstractPowerAction;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -31,22 +30,22 @@ public final class MobLoot extends Item {
private String prefix = ""; private String prefix = "";
private String suffix = ""; private String suffix = "";
public MobLoot(AbstractCharacter mob, CObjectTemplate template, boolean noSteal) { public MobLoot(AbstractCharacter mob, ItemTemplate template, boolean noSteal) {
this(mob, template, 0, noSteal); this(mob, template, 0, noSteal);
} }
public MobLoot(AbstractCharacter mob, int qtyOfGold) { public MobLoot(AbstractCharacter mob, int qtyOfGold) {
this(mob, CObjectTemplate.lookup(mbEnums.ResourceType.GOLD.templateID), qtyOfGold, false); this(mob, ItemTemplate.templates.get(mbEnums.ResourceType.GOLD.templateID), qtyOfGold, false);
} }
public MobLoot(AbstractCharacter mob, CObjectTemplate template, int quantity, boolean noSteal) { public MobLoot(AbstractCharacter mob, ItemTemplate template, int quantity, boolean noSteal) {
super(template.getTemplateId()); super(template.template_id);
this.ownerType = OwnerType.Mob; this.ownerType = OwnerType.Mob;
this.ownerID = mob.getObjectUUID(); this.ownerID = mob.getObjectUUID();
this.objectUUID = generateId(); this.objectUUID = generateId();
if (quantity == 0 && template.getItemType() == ItemType.RESOURCE) if (quantity == 0 && template.item_type == ItemType.RESOURCE)
quantity = 1; quantity = 1;
if (quantity > 0) if (quantity > 0)
@@ -106,7 +105,7 @@ public final class MobLoot extends Item {
if (isDeleted) if (isDeleted)
return null; return null;
if (this.template.getItemType().equals(ItemType.GOLD)) if (this.template.item_type.equals(ItemType.GOLD))
return null; return null;
Item item = this; Item item = this;
+15 -15
View File
@@ -23,9 +23,9 @@ import engine.net.ByteBufferWriter;
import engine.net.Dispatch; import engine.net.Dispatch;
import engine.net.client.msg.PetMsg; import engine.net.client.msg.PetMsg;
import engine.net.client.msg.PlaceAssetMsg; import engine.net.client.msg.PlaceAssetMsg;
import engine.parsers.objects.CObjectTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import java.time.LocalDateTime;
import java.time.ZoneId;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
@@ -68,7 +68,7 @@ public class NPC extends AbstractCharacter {
protected int symbol; protected int symbol;
// Variables NOT to be stored in db // Variables NOT to be stored in db
protected boolean isStatic = false; protected boolean isStatic = false;
private DateTime upgradeDateTime = null; private LocalDateTime upgradeDateTime = null;
private HashSet<Integer> canRoll = null; private HashSet<Integer> canRoll = null;
public int parentZoneUUID; public int parentZoneUUID;
public int equipmentSetID = 0; public int equipmentSetID = 0;
@@ -132,7 +132,7 @@ public class NPC extends AbstractCharacter {
sqlDateTime = rs.getTimestamp("upgradeDate"); sqlDateTime = rs.getTimestamp("upgradeDate");
if (sqlDateTime != null) if (sqlDateTime != null)
upgradeDateTime = new DateTime(sqlDateTime); upgradeDateTime = LocalDateTime.ofInstant(sqlDateTime.toInstant(), ZoneId.systemDefault());
else else
upgradeDateTime = null; upgradeDateTime = null;
@@ -528,9 +528,9 @@ public class NPC extends AbstractCharacter {
// Submit upgrade job for future date or current instant // Submit upgrade job for future date or current instant
if (this.getUpgradeDateTime().isAfter(DateTime.now())) if (this.getUpgradeDateTime().isAfter(LocalDateTime.now()))
jc = JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(this), jc = JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(this),
this.getUpgradeDateTime().getMillis()); this.getUpgradeDateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
else else
JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(this), 0); JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(this), 0);
@@ -908,7 +908,7 @@ public class NPC extends AbstractCharacter {
return new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); return new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
} }
public DateTime getUpgradeDateTime() { public LocalDateTime getUpgradeDateTime() {
lock.readLock().lock(); lock.readLock().lock();
try { try {
return upgradeDateTime; return upgradeDateTime;
@@ -917,7 +917,7 @@ public class NPC extends AbstractCharacter {
} }
} }
public void setUpgradeDateTime(DateTime upgradeDateTime) { public void setUpgradeDateTime(LocalDateTime upgradeDateTime) {
if (!DbManager.NPCQueries.updateUpgradeTime(this, upgradeDateTime)) { if (!DbManager.NPCQueries.updateUpgradeTime(this, upgradeDateTime)) {
Logger.error("Failed to set upgradeTime for building " + currentID); Logger.error("Failed to set upgradeTime for building " + currentID);
@@ -962,15 +962,15 @@ public class NPC extends AbstractCharacter {
maxSkill = 110; maxSkill = 110;
break; break;
} }
CObjectTemplate itemTemplate; ItemTemplate itemTemplate;
int skillRequired = 0; int skillRequired = 0;
for (Integer itemID : fullItemList) { for (Integer itemID : fullItemList) {
itemTemplate = CObjectTemplate.lookup(itemID); itemTemplate = ItemTemplate.templates.get(itemID);
if (itemTemplate.getItemSkillReq().values().iterator().hasNext()) if (itemTemplate.item_skill_required.values().iterator().hasNext())
skillRequired = itemTemplate.getItemSkillReq().values().iterator().next(); skillRequired = itemTemplate.item_skill_required.values().iterator().next();
boolean exclude = skillRequired == 0 && CObjectTemplate.lookup(itemID).getItemType().equals(ItemType.WEAPON); boolean exclude = skillRequired == 0 && ItemTemplate.templates.get(itemID).item_type.equals(ItemType.WEAPON);
if (skillRequired <= maxSkill && !exclude) if (skillRequired <= maxSkill && !exclude)
filteredItemList.add(itemID); filteredItemList.add(itemID);
} }
@@ -1060,7 +1060,7 @@ public class NPC extends AbstractCharacter {
int rankCost; int rankCost;
Building building; Building building;
DateTime dateToUpgrade; LocalDateTime dateToUpgrade;
this.lock.writeLock().lock(); this.lock.writeLock().lock();
@@ -1103,7 +1103,7 @@ public class NPC extends AbstractCharacter {
if (!building.transferGold(-rankCost, false)) if (!building.transferGold(-rankCost, false))
return; return;
dateToUpgrade = DateTime.now().plusHours(this.getUpgradeTime()); dateToUpgrade = LocalDateTime.now().plusHours(this.getUpgradeTime());
this.setUpgradeDateTime(dateToUpgrade); this.setUpgradeDateTime(dateToUpgrade);
+3 -3
View File
@@ -33,7 +33,7 @@ public class NPCRune extends AbstractGameObject {
this.runeBase = runeBase; this.runeBase = runeBase;
this.player = characterID; this.player = characterID;
if (this.runeBase != null) if (this.runeBase != null)
this.skillsGranted = SkillReq.getSkillReqsForRune(this.runeBase.getObjectUUID()); this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(this.runeBase.getObjectUUID());
else else
this.skillsGranted = new ArrayList<>(); this.skillsGranted = new ArrayList<>();
this.effectsGranted = new ArrayList<>(); this.effectsGranted = new ArrayList<>();
@@ -47,7 +47,7 @@ public class NPCRune extends AbstractGameObject {
this.runeBase = runeBase; this.runeBase = runeBase;
this.player = characterID; this.player = characterID;
if (this.runeBase == null) if (this.runeBase == null)
this.skillsGranted = SkillReq.getSkillReqsForRune(this.runeBase.getObjectUUID()); this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(this.runeBase.getObjectUUID());
else else
this.skillsGranted = new ArrayList<>(); this.skillsGranted = new ArrayList<>();
this.effectsGranted = new ArrayList<>(); this.effectsGranted = new ArrayList<>();
@@ -62,7 +62,7 @@ public class NPCRune extends AbstractGameObject {
this.runeBase = RuneBase.getRuneBase(rs.getInt("RuneBaseID")); this.runeBase = RuneBase.getRuneBase(rs.getInt("RuneBaseID"));
this.player = rs.getInt("NpcID"); this.player = rs.getInt("NpcID");
if (this.runeBase != null) { if (this.runeBase != null) {
this.skillsGranted = SkillReq.getSkillReqsForRune(this.runeBase.getObjectUUID()); this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(this.runeBase.getObjectUUID());
this.effectsGranted = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE(this.runeBase.getObjectUUID()); this.effectsGranted = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE(this.runeBase.getObjectUUID());
} else { } else {
Logger.error("Failed to find RuneBase for NPCRune " + this.getObjectUUID()); Logger.error("Failed to find RuneBase for NPCRune " + this.getObjectUUID());
+74 -70
View File
@@ -32,13 +32,13 @@ import engine.net.Dispatch;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.*; import engine.net.client.msg.*;
import engine.net.client.msg.login.CommitNewCharacterMsg; import engine.net.client.msg.login.CommitNewCharacterMsg;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.server.login.LoginServer; import engine.server.login.LoginServer;
import engine.server.world.WorldServer; import engine.server.world.WorldServer;
import engine.util.MiscUtils; import engine.util.MiscUtils;
import org.joda.time.DateTime; import java.time.Instant;
import java.time.ZoneId;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
@@ -703,11 +703,11 @@ public class PlayerCharacter extends AbstractCharacter {
writer.putInt(token); writer.putInt(token);
writer.putInt((int) timeLeft / 1000); writer.putInt((int) timeLeft / 1000);
} }
DateTime enterWorld = new DateTime(playerCharacter.timestamps.get("EnterWorld")); Instant enterWorld = Instant.ofEpochMilli(playerCharacter.timestamps.get("EnterWorld"));
writer.putDateTime(enterWorld); writer.putDateTime(enterWorld);
writer.putInt(0x49EF1E98); //DUnno what playerCharacter is. writer.putInt(0x49EF1E98); //DUnno what playerCharacter is.
writer.putFloat(DateTime.now().hourOfDay().get()); //daylight in float. writer.putFloat(Instant.now().atZone(ZoneId.systemDefault()).toLocalTime().getHour()); //daylight in float.
writer.putFloat(6); //interval of light to change per game hour //float writer.putFloat(6); //interval of light to change per game hour //float
//writer.putInt(1637194901); //playerCharacter is actually an opcode taht is in recordings, no clue what it is, dumped it and it changes nothing //writer.putInt(1637194901); //playerCharacter is actually an opcode taht is in recordings, no clue what it is, dumped it and it changes nothing
} else { } else {
@@ -730,14 +730,6 @@ public class PlayerCharacter extends AbstractCharacter {
} }
// The client enforces these rules, so a refusal usually means a modified client.
private static PlayerCharacter refuseCreation(Account account, ClientConnection clientConnection, String reason) {
Logger.warn("Character creation refused: " + reason + " ACCOUNT: " + account.getUname() + "(" + account.getObjectUUID()
+ ") IP ADDRESS: " + clientConnection.getClientIpAddress());
return null;
}
public static PlayerCharacter generatePCFromCommitNewCharacterMsg(Account a, CommitNewCharacterMsg msg, ClientConnection clientConnection) { public static PlayerCharacter generatePCFromCommitNewCharacterMsg(Account a, CommitNewCharacterMsg msg, ClientConnection clientConnection) {
String firstName = msg.getFirstName().trim(); String firstName = msg.getFirstName().trim();
@@ -776,7 +768,8 @@ public class PlayerCharacter extends AbstractCharacter {
Race race = Race.getRace(raceID); Race race = Race.getRace(raceID);
if (race == null) { if (race == null) {
return refuseCreation(a, clientConnection, "Invalid RaceID: " + raceID); Logger.info("Invalid RaceID: " + raceID);
return null;
} }
// Verify BaseClass Object. // Verify BaseClass Object.
@@ -784,7 +777,8 @@ public class PlayerCharacter extends AbstractCharacter {
BaseClass baseClass = DbManager.BaseClassQueries.GET_BASE_CLASS(baseClassID); BaseClass baseClass = DbManager.BaseClassQueries.GET_BASE_CLASS(baseClassID);
if (baseClass == null) { if (baseClass == null) {
return refuseCreation(a, clientConnection, "Invalid BaseClasID: " + baseClassID); Logger.info("Invalid BaseClasID: " + baseClassID);
return null;
} }
// Verify Race/baseClass combo. // Verify Race/baseClass combo.
@@ -799,7 +793,8 @@ public class PlayerCharacter extends AbstractCharacter {
} }
if (!valid) { if (!valid) {
return refuseCreation(a, clientConnection, "Invalid BaseClass/Race Combo"); Logger.info("Invalid BaseClass/Race Combo");
return null;
} }
// Verify HairStyle/BeardStyle/SkinColor/HairColor/BeardColor // Verify HairStyle/BeardStyle/SkinColor/HairColor/BeardColor
@@ -810,19 +805,23 @@ public class PlayerCharacter extends AbstractCharacter {
int beardColorID = msg.getBeardColor(); int beardColorID = msg.getBeardColor();
if (!race.isValidHairStyle(hairStyleID)) { if (!race.isValidHairStyle(hairStyleID)) {
return refuseCreation(a, clientConnection, "Invalid HairStyleID: " + hairStyleID + " for race: " + race.getName()); Logger.info("Invalid HairStyleID: " + hairStyleID + " for race: " + race.getName());
return null;
} }
if (!race.isValidSkinColor(skinColorID)) { if (!race.isValidSkinColor(skinColorID)) {
return refuseCreation(a, clientConnection, "Invalid skinColorID: " + skinColorID + " for race: " + race.getName()); Logger.info("Invalid skinColorID: " + skinColorID + " for race: " + race.getName());
return null;
} }
if (!race.isValidHairColor(hairColorID)) { if (!race.isValidHairColor(hairColorID)) {
return refuseCreation(a, clientConnection, "Invalid hairColorID: " + hairColorID + " for race: " + race.getName()); Logger.info("Invalid hairColorID: " + hairColorID + " for race: " + race.getName());
return null;
} }
if (!race.isValidBeardColor(beardColorID)) { if (!race.isValidBeardColor(beardColorID)) {
return refuseCreation(a, clientConnection, "Invalid beardColorID: " + beardColorID + " for race: " + race.getName()); Logger.info("Invalid beardColorID: " + beardColorID + " for race: " + race.getName());
return null;
} }
// Get stat modifiers // Get stat modifiers
@@ -834,7 +833,8 @@ public class PlayerCharacter extends AbstractCharacter {
if (intMod < -5 || dexMod < -5 || conMod < -5 || strMod < -5 || spiMod < -5) { if (intMod < -5 || dexMod < -5 || conMod < -5 || strMod < -5 || spiMod < -5) {
return refuseCreation(a, clientConnection, "Negative stat mod"); Logger.error("NEGATIVE STAT CHEAT ATTEMPTED! ACCOUNT: " + a.getUname() + "(" + a.getObjectUUID() + ") IP ADDRESS: " + clientConnection.getClientIpAddress());
return null;
} }
// calculate current stats: // calculate current stats:
@@ -851,11 +851,12 @@ public class PlayerCharacter extends AbstractCharacter {
short intMax = race.getIntMax(); short intMax = race.getIntMax();
short spiMax = race.getSpiMax(); short spiMax = race.getSpiMax();
// 10 rune slots including race and class (client 0xBA8C80) // Verify not too many runes applied
int numRunes = msg.getNumRunes(); int numRunes = msg.getNumRunes();
if (numRunes > 10) { if (numRunes > 16) {
return refuseCreation(a, clientConnection, "Too many Runes applied"); Logger.info("Too many Runes applied");
return null;
} }
// Get Runes // Get Runes
@@ -865,8 +866,7 @@ public class PlayerCharacter extends AbstractCharacter {
int[] characterRunes = msg.getRunes(); int[] characterRunes = msg.getRunes();
HashSet<Integer> usedRuneIDs = new HashSet<>(); HashSet<Byte> usedRunesSubType = new HashSet<>();
HashSet<Integer> usedSubTypeTokens = new HashSet<>();
HashSet<RuneBase> usedRunes = new HashSet<>(); HashSet<RuneBase> usedRunes = new HashSet<>();
// So that all the penalties can be added at the end. // So that all the penalties can be added at the end.
@@ -906,33 +906,38 @@ public class PlayerCharacter extends AbstractCharacter {
// Null check // Null check
if (runeBase == null) { if (runeBase == null) {
return refuseCreation(a, clientConnection, "GOM returned NULL RuneBase"); Logger.info("GOM returned NULL RuneBase");
return null;
} }
// Validate Rune against Race // Validate Rune against Race
if (!race.isAllowedRune(runeBase)) { if (!race.isAllowedRune(runeBase)) {
return refuseCreation(a, clientConnection, "Trait Not valid for Race"); Logger.info("Trait Not valid for Race");
return null;
} }
// Validate BaseClass against Race // Validate BaseClass against Race
if (!baseClass.isAllowedRune(runeBase)) { if (!baseClass.isAllowedRune(runeBase)) {
return refuseCreation(a, clientConnection, "Trait Not valid for BaseClass"); Logger.info("Trait Not valid for BaseClass");
return null;
} }
if (!usedRuneIDs.add(runeBase.getObjectUUID())) { int previous_size = usedRunes.size();
return refuseCreation(a, clientConnection, "Duplicate RuneBase"); int previous_subtype = usedRunesSubType.size();
}
// Creation talents are rank 0, so two of the same sub type block each other (client 0x4695D0)
if (runeBase.getSubTypeToken() != 0 && !usedSubTypeTokens.add(runeBase.getSubTypeToken())) {
return refuseCreation(a, clientConnection, "Duplicate RuneBase Subtype");
}
usedRunes.add(runeBase); usedRunes.add(runeBase);
usedRunesSubType.add(runeBase.getSubtype());
// Talent cap of 8 (client 0x4695D0) // Duplicate Rune check
if (usedRunes.size() > 8) { if (usedRunes.size() <= previous_size) {
return refuseCreation(a, clientConnection, "Too many talents applied"); Logger.info("Duplicate RuneBase");
return null;
}
// Duplicate Subtype check
if (runeBase.getSubtype() != 0 && usedRunesSubType.size() <= previous_subtype) {
Logger.info("Duplicate RuneBase Subtype");
return null;
} }
int maxValue = 0; int maxValue = 0;
@@ -977,37 +982,43 @@ public class PlayerCharacter extends AbstractCharacter {
remainingPoints -= value; remainingPoints -= value;
continue; continue;
} }
return refuseCreation(a, clientConnection, "Not enough points left"); Logger.info("Not enough points left");
return null;
case MBServerStatics.RUNE_STR_MIN_NEEDED_ATTRIBUTE_ID: case MBServerStatics.RUNE_STR_MIN_NEEDED_ATTRIBUTE_ID:
if (strCur >= value) if (strCur >= value)
continue; continue;
return refuseCreation(a, clientConnection, "STR fails to meet Rune Minimum --> " + rb.getName()); Logger.info("STR fails to meet Rune Minimum --> " + rb.getName());
return null;
case MBServerStatics.RUNE_DEX_MIN_NEEDED_ATTRIBUTE_ID: case MBServerStatics.RUNE_DEX_MIN_NEEDED_ATTRIBUTE_ID:
if (dexCur >= value) if (dexCur >= value)
continue; continue;
return refuseCreation(a, clientConnection, "DEX fails to meet Rune Minimum --> " + rb.getName()); Logger.info("DEX fails to meet Rune Minimum --> " + rb.getName());
return null;
case MBServerStatics.RUNE_CON_MIN_NEEDED_ATTRIBUTE_ID: case MBServerStatics.RUNE_CON_MIN_NEEDED_ATTRIBUTE_ID:
if (conCur >= value) if (conCur >= value)
continue; continue;
return refuseCreation(a, clientConnection, "CON fails to meet Rune Minimum --> " + rb.getName()); Logger.info("CON fails to meet Rune Minimum --> " + rb.getName());
return null;
case MBServerStatics.RUNE_INT_MIN_NEEDED_ATTRIBUTE_ID: case MBServerStatics.RUNE_INT_MIN_NEEDED_ATTRIBUTE_ID:
if (intCur >= value) if (intCur >= value)
continue; continue;
return refuseCreation(a, clientConnection, "INT fails to meet Rune Minimum --> " + rb.getName()); Logger.info("INT fails to meet Rune Minimum --> " + rb.getName());
return null;
case MBServerStatics.RUNE_SPI_MIN_NEEDED_ATTRIBUTE_ID: case MBServerStatics.RUNE_SPI_MIN_NEEDED_ATTRIBUTE_ID:
if (spiCur >= value) if (spiCur >= value)
continue; continue;
return refuseCreation(a, clientConnection, "SPI fails to meet Rune Minimum --> " + rb.getName()); Logger.info("SPI fails to meet Rune Minimum --> " + rb.getName());
return null;
case MBServerStatics.RUNE_STR_ATTRIBUTE_ID: case MBServerStatics.RUNE_STR_ATTRIBUTE_ID:
if (value < 0) if (value < 0)
@@ -1072,20 +1083,12 @@ public class PlayerCharacter extends AbstractCharacter {
continue; continue;
default: default:
return refuseCreation(a, clientConnection, "Unknown ATTRIBUTE_ID while checking RuneBaseAttributes: " + attrID); Logger.info("Unknown ATTRIBUTE_ID while checking RuneBaseAttributes: " + attrID);
return null;
} }
} }
} }
// Checked before the penalties, as the client's +/- does (0xBAC140): Giant's Blood cuts a max below its stat
if (strCur < 1 || dexCur < 1 || conCur < 1 || intCur < 1 || spiCur < 1) {
return refuseCreation(a, clientConnection, "Attribute below 1");
}
if (strCur > strMax || dexCur > dexMax || conCur > conMax || intCur > intMax || spiCur > spiMax) {
return refuseCreation(a, clientConnection, "Attribute above racial maximum");
}
// Add in all of the penalties. // Add in all of the penalties.
strCur += penalties.get("StrCur"); strCur += penalties.get("StrCur");
strMax += penalties.get("StrMax"); strMax += penalties.get("StrMax");
@@ -1114,7 +1117,8 @@ public class PlayerCharacter extends AbstractCharacter {
} }
if (kit == null) { if (kit == null) {
return refuseCreation(a, clientConnection, "Unable to find matching kitID: " + kitID); Logger.info("Unable to find matching kitID: " + kitID);
return null;
} }
byte runningTrains = 0; byte runningTrains = 0;
@@ -1350,10 +1354,10 @@ public class PlayerCharacter extends AbstractCharacter {
public static float getDexPenalty(Item armor) { public static float getDexPenalty(Item armor) {
if (armor == null) if (armor == null)
return 0f; return 0f;
CObjectTemplate ab = armor.template; ItemTemplate ab = armor.template;
if (ab == null) if (ab == null)
return 0f; return 0f;
return engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_bulk_factor; return ab.item_bulk_factor;
} }
public static void InitializeSkillsOnLoad(PlayerCharacter pc) { public static void InitializeSkillsOnLoad(PlayerCharacter pc) {
@@ -2813,15 +2817,15 @@ public class PlayerCharacter extends AbstractCharacter {
if (item == null) if (item == null)
return false; return false;
CObjectTemplate ib = item.template; ItemTemplate ib = item.template;
if (ib != null) { if (ib != null) {
if ((item.template.getItemType().equals(ItemType.WEAPON)) if ((item.template.item_type.equals(ItemType.WEAPON))
&& (item.template.getItemSkillUsed().equals(type) || ib.getItemSkillMasteryUsed().equals(type))) && (item.template.item_skill_used.equals(type) || ib.item_skill_mastery_used.equals(type)))
return true; return true;
return (item.template.getItemType().equals(ItemType.ARMOR)) return (item.template.item_type.equals(ItemType.ARMOR))
&& (item.template.getItemSkillUsed().equals(type)); && (item.template.item_skill_used.equals(type));
} }
return false; return false;
@@ -3765,8 +3769,8 @@ public class PlayerCharacter extends AbstractCharacter {
ConcurrentHashMap<EquipSlotType, Item> equipped = this.charItemManager.getEquipped(); ConcurrentHashMap<EquipSlotType, Item> equipped = this.charItemManager.getEquipped();
Item off = equipped.get(EquipSlotType.LHELD); Item off = equipped.get(EquipSlotType.LHELD);
Item main = equipped.get(EquipSlotType.RHELD); Item main = equipped.get(EquipSlotType.RHELD);
CObjectTemplate wbMain = null; ItemTemplate wbMain = null;
CObjectTemplate wbOff = null; ItemTemplate wbOff = null;
if (main != null) if (main != null)
wbMain = main.template; wbMain = main.template;
if (off != null) if (off != null)
@@ -3788,8 +3792,8 @@ public class PlayerCharacter extends AbstractCharacter {
this.bonuses.setBool(ModType.Parry, SourceType.None, false); this.bonuses.setBool(ModType.Parry, SourceType.None, false);
if ((this.baseClass != null && this.baseClass.getObjectUUID() == 2500) if ((this.baseClass != null && this.baseClass.getObjectUUID() == 2500)
|| (this.promotionClass != null && this.promotionClass.getObjectUUID() == 2520)) || (this.promotionClass != null && this.promotionClass.getObjectUUID() == 2520))
if (wbMain == null || engine.parsers.objects.ItemTemplate.getWeapon(wbMain.getTemplateId()).weapon_max_range < MBServerStatics.RANGED_WEAPON_RANGE) if (wbMain == null || wbMain.item_weapon_max_range < MBServerStatics.RANGED_WEAPON_RANGE)
if (wbOff == null || engine.parsers.objects.ItemTemplate.getWeapon(wbOff.getTemplateId()).weapon_max_range < MBServerStatics.RANGED_WEAPON_RANGE) if (wbOff == null || wbOff.item_weapon_max_range < MBServerStatics.RANGED_WEAPON_RANGE)
this.bonuses.setBool(ModType.Parry, SourceType.None, true); this.bonuses.setBool(ModType.Parry, SourceType.None, true);
} }
@@ -4181,9 +4185,8 @@ public class PlayerCharacter extends AbstractCharacter {
} else if (currentPet.isSiege()) { } else if (currentPet.isSiege()) {
currentPet.agentType = AIAgentType.MOBILE; currentPet.agentType = AIAgentType.MOBILE;
// released siege engine keeps its current target
currentPet.guardCaptain = null; currentPet.guardCaptain = null;
currentPet.setCombatTarget(null);
if (currentPet.isAlive()) if (currentPet.isAlive())
WorldGrid.updateObject(currentPet); WorldGrid.updateObject(currentPet);
} }
@@ -4191,6 +4194,7 @@ public class PlayerCharacter extends AbstractCharacter {
toCommand.setPet(this, false); toCommand.setPet(this, false);
this.setPet(toCommand); this.setPet(toCommand);
toCommand.setCombatTarget(null);
PetMsg petMsg = new PetMsg(6, toCommand); PetMsg petMsg = new PetMsg(6, toCommand);
Dispatch dispatch = Dispatch.borrow(this, petMsg); Dispatch dispatch = Dispatch.borrow(this, petMsg);
DispatchManager.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); DispatchManager.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
@@ -4361,7 +4365,7 @@ public class PlayerCharacter extends AbstractCharacter {
} }
if (count > 0) { if (count > 0) {
this.timestamps.put("RealmClaim", DateTime.now().plusMinutes(3).getMillis()); this.timestamps.put("RealmClaim", Instant.now().plusSeconds(180).toEpochMilli());
for (PlayerCharacter toSend : SessionManager.getAllActivePlayerCharacters()) { for (PlayerCharacter toSend : SessionManager.getAllActivePlayerCharacters()) {
ChatManager.chatSystemInfo(toSend, this.getCombinedName() + " is seeking to claim a realm and already has " + count + " blessngs!"); ChatManager.chatSystemInfo(toSend, this.getCombinedName() + " is seeking to claim a realm and already has " + count + " blessngs!");
} }
@@ -10,10 +10,7 @@
package engine.objects; package engine.objects;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.mbEnums;
import engine.parsers.objects.RuneTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.util.Hasher;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@@ -21,28 +18,24 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class PowerGrantedTrains { public class PowerGrant extends AbstractGameObject {
private static ConcurrentHashMap<Integer, PowerGrantedTrains> grantedPowers = null; private static ConcurrentHashMap<Integer, PowerGrant> grantedPowers = null;
private int token; private int token;
private ConcurrentHashMap<Integer, Short> runeGrants = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); private ConcurrentHashMap<Integer, Short> runeGrants = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
/** /**
* ResultSet Constructor * ResultSet Constructor
*/ */
public PowerGrantedTrains(ResultSet rs) throws SQLException { public PowerGrant(ResultSet rs) throws SQLException {
super();
this.token = rs.getInt("powerToken"); this.token = rs.getInt("powerToken");
runeGrants.put(rs.getInt("runeID"), rs.getShort("grantAmount")); runeGrants.put(rs.getInt("runeID"), rs.getShort("grantAmount"));
} }
public PowerGrantedTrains(int token) {
this.token = token;
}
/* /*
* Getters * Getters
*/ */
@@ -51,11 +44,11 @@ public class PowerGrantedTrains {
if (pc == null) if (pc == null)
return (short) 0; return (short) 0;
if (PowerGrantedTrains.grantedPowers == null) if (PowerGrant.grantedPowers == null)
loadGrantedPowers(); fillGrantedPowers();
if (PowerGrantedTrains.grantedPowers.containsKey(token)) { if (PowerGrant.grantedPowers.containsKey(token)) {
PowerGrantedTrains pg = PowerGrantedTrains.grantedPowers.get(token); PowerGrant pg = PowerGrant.grantedPowers.get(token);
ConcurrentHashMap<Integer, Short> runeGrants = pg.runeGrants; ConcurrentHashMap<Integer, Short> runeGrants = pg.runeGrants;
ArrayList<Integer> toks = new ArrayList<>(); ArrayList<Integer> toks = new ArrayList<>();
@@ -95,38 +88,9 @@ public class PowerGrantedTrains {
return (short) 0; return (short) 0;
} }
// Trains are power_arguments[0] of the first action. Mob race runes are skipped:
// their power actions are mob power ranks by level, not trains.
public static void loadGrantedPowers() {
ConcurrentHashMap<Integer, PowerGrantedTrains> powerGrants = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
int token;
int grantCount = 0;
for (RuneTemplate rune : RuneTemplate._runes.values()) {
if (rune.rune_type == mbEnums.RuneType.RACE && Race.getRace(rune.template_id) == null)
continue;
for (Map.Entry<String, ArrayList<int[]>> powerAction : rune.item_power_action.entrySet()) {
if (powerAction.getValue().isEmpty())
continue;
token = Hasher.SBStringHash(powerAction.getKey());
powerGrants.computeIfAbsent(token, PowerGrantedTrains::new)
.addRuneGrant(rune.template_id, (short) powerAction.getValue().get(0)[0]);
grantCount++;
}
}
PowerGrantedTrains.grantedPowers = powerGrants;
Logger.info("Loaded " + grantCount + " power train grants for " + powerGrants.size() + " powers");
}
public static void fillGrantedPowers() { public static void fillGrantedPowers() {
PowerGrantedTrains.grantedPowers = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); PowerGrant.grantedPowers = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM static_power_powergrant")) { PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM static_power_powergrant")) {
@@ -134,7 +98,7 @@ public class PowerGrantedTrains {
ResultSet rs = preparedStatement.executeQuery(); ResultSet rs = preparedStatement.executeQuery();
if (PowerGrantedTrains.grantedPowers.size() > 0) { if (PowerGrant.grantedPowers.size() > 0) {
rs.close(); rs.close();
return; return;
} }
@@ -143,14 +107,14 @@ public class PowerGrantedTrains {
int token = rs.getInt("powerToken"); int token = rs.getInt("powerToken");
PowerGrantedTrains pg; PowerGrant pg;
if (PowerGrantedTrains.grantedPowers.containsKey(token)) { if (PowerGrant.grantedPowers.containsKey(token)) {
pg = PowerGrantedTrains.grantedPowers.get(token); pg = PowerGrant.grantedPowers.get(token);
pg.addRuneGrant(rs.getInt("runeID"), rs.getShort("grantAmount")); pg.addRuneGrant(rs.getInt("runeID"), rs.getShort("grantAmount"));
} else { } else {
pg = new PowerGrantedTrains(rs); pg = new PowerGrant(rs);
PowerGrantedTrains.grantedPowers.put(token, pg); PowerGrant.grantedPowers.put(token, pg);
} }
} }
rs.close(); rs.close();
@@ -170,4 +134,8 @@ public class PowerGrantedTrains {
private void addRuneGrant(int runeID, short amount) { private void addRuneGrant(int runeID, short amount) {
this.runeGrants.put(runeID, amount); this.runeGrants.put(runeID, amount);
} }
@Override
public void updateDatabase() {
}
} }
+2 -80
View File
@@ -10,13 +10,8 @@
package engine.objects; package engine.objects;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.mbEnums;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.parsers.cache.CObjectIndex;
import engine.parsers.objects.RuneTemplate;
import engine.util.Hasher;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -96,91 +91,18 @@ public class PromotionClass extends AbstractGameObject {
this.manaMod = rs.getFloat("manaMod"); this.manaMod = rs.getFloat("manaMod");
this.staminaMod = rs.getFloat("staminaMod"); this.staminaMod = rs.getFloat("staminaMod");
this.allowedRunes = DbManager.PromotionQueries.GET_ALLOWED_RUNES(this); this.allowedRunes = DbManager.PromotionQueries.GET_ALLOWED_RUNES(this);
this.skillsGranted = SkillReq.getSkillReqsForRune(this.getObjectUUID()); this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(this.getObjectUUID());
this.powersGranted = PowerReq.getPowerReqsForRune(this.getObjectUUID()); this.powersGranted = PowerReq.getPowerReqsForRune(this.getObjectUUID());
this.effectsGranted = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE(this.getObjectUUID()); this.effectsGranted = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE(this.getObjectUUID());
this.effectsGrantedFighter = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2500); this.effectsGrantedFighter = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2500);
this.effectsGrantedHealer = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2501); this.effectsGrantedHealer = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2501);
this.effectsGrantedRogue = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2502); this.effectsGrantedRogue = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2502);
this.effectsGrantedMage = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2503); this.effectsGrantedMage = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2503);
this.effectsList = MobBaseEffects.getEffectsForRune(this.getObjectUUID()); this.effectsList = DbManager.MobBaseQueries.GET_RUNEBASE_EFFECTS(this.getObjectUUID());
} }
/**
* Rune Template Constructor
*/
public PromotionClass(RuneTemplate rune) {
super(rune.template_id);
this.name = rune.obj_name;
this.description = rune.rune_dsc;
this.token = Hasher.SBStringHash(rune.rune_sub_type);
this.healthMod = rune.rune_health;
this.manaMod = rune.rune_mana;
this.staminaMod = rune.rune_stamina;
this.allowedRunes = getAllowedRuneTokens(rune);
this.skillsGranted = SkillReq.getSkillReqsForRune(this.getObjectUUID());
this.powersGranted = PowerReq.getPowerReqsForRune(this.getObjectUUID());
this.effectsGranted = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE(this.getObjectUUID());
this.effectsGrantedFighter = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2500);
this.effectsGrantedHealer = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2501);
this.effectsGrantedRogue = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2502);
this.effectsGrantedMage = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2503);
this.effectsList = MobBaseEffects.getEffectsForRune(this.getObjectUUID());
}
// Promotions are the CLASS runes that require a base class; this skips the creation classes and Pet 2522.
public static boolean isPromotionRune(RuneTemplate rune) {
return rune.rune_type == mbEnums.RuneType.CLASS && !rune.rune_is_standard_character_creation
&& !rune.item_class_req.isEmpty();
}
// Race and base class tokens are SBStringHash(rune_sub_type) of the runes named in the req lists.
// Every promotion rune's lists are whitelists (restrict false).
private static ArrayList<Integer> getAllowedRuneTokens(RuneTemplate rune) {
ArrayList<Integer> tokens = new ArrayList<>();
Integer classRuneId;
int token;
for (mbEnums.MonsterType race : rune.item_race_req)
for (int raceRuneId : CObjectIndex.getRaceRuneIds(race)) {
token = Hasher.SBStringHash(RuneTemplate._runes.get(raceRuneId).rune_sub_type);
if (!tokens.contains(token))
tokens.add(token);
}
for (mbEnums.ClassType classType : rune.item_class_req) {
classRuneId = CObjectIndex.getClassRuneId(classType);
if (classRuneId != null)
tokens.add(Hasher.SBStringHash(RuneTemplate._runes.get(classRuneId).rune_sub_type));
}
return tokens;
}
public static void LoadAllPromotions() {
int loadedCount = 0;
for (RuneTemplate rune : RuneTemplate._runes.values()) {
if (!isPromotionRune(rune))
continue;
DbManager.addToCache(new PromotionClass(rune));
loadedCount++;
}
Logger.info("Loaded " + loadedCount + " promotion classes from runes");
// The CSR/admin rows 2901+ have no promotion rune; the DB loader skips ids already cached
DbManager.PromotionQueries.GET_ALL_PROMOTIONS();
}
public static void serializeForClientMsg(PromotionClass promotionClass, ByteBufferWriter writer) { public static void serializeForClientMsg(PromotionClass promotionClass, ByteBufferWriter writer) {
writer.putInt(3); // For BaseClass writer.putInt(3); // For BaseClass
writer.putInt(0); // Pad writer.putInt(0); // Pad
+3 -108
View File
@@ -13,11 +13,7 @@ import engine.gameManager.DbManager;
import engine.mbEnums; import engine.mbEnums;
import engine.mbEnums.RaceType; import engine.mbEnums.RaceType;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.parsers.cache.CacheParserUtil;
import engine.parsers.objects.RuneTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.util.Hasher;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -31,9 +27,6 @@ public class Race {
private static ConcurrentHashMap<Integer, Race> _raceByID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); private static ConcurrentHashMap<Integer, Race> _raceByID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
// Creation points before the race rune's rune_creation_cost is taken off
private static final int STARTING_POINT_POOL = 30;
private final String name; private final String name;
private final String description; private final String description;
private final int raceRuneID; private final int raceRuneID;
@@ -108,112 +101,14 @@ public class Race {
this.beardColors = DbManager.RaceQueries.BEARD_COLORS_FOR_RACE(raceRuneID); this.beardColors = DbManager.RaceQueries.BEARD_COLORS_FOR_RACE(raceRuneID);
this.hairColors = DbManager.RaceQueries.HAIR_COLORS_FOR_RACE(raceRuneID); this.hairColors = DbManager.RaceQueries.HAIR_COLORS_FOR_RACE(raceRuneID);
this.baseClasses = DbManager.BaseClassQueries.GET_BASECLASS_FOR_RACE(raceRuneID); this.baseClasses = DbManager.BaseClassQueries.GET_BASECLASS_FOR_RACE(raceRuneID);
this.skillsGranted = SkillReq.getSkillReqsForRune(raceRuneID); this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(raceRuneID);
this.powersGranted = PowerReq.getPowerReqsForRune(raceRuneID); this.powersGranted = PowerReq.getPowerReqsForRune(raceRuneID);
this.effectsList = MobBaseEffects.getEffectsForRune(this.raceRuneID); this.effectsList = DbManager.MobBaseQueries.GET_RUNEBASE_EFFECTS(this.raceRuneID);
} }
/**
* Rune Template Constructor
* minHeight and strHeightMod are server-only and come from the static_rune_race row.
*/
public Race(RuneTemplate rune, Race dbRace) {
this.raceRuneID = rune.template_id;
this.raceType = mbEnums.RaceType.getRaceTypebyRuneID(raceRuneID);
this.name = rune.obj_name;
this.description = rune.rune_dsc;
this.strStart = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Strength, 0).shortValue();
this.strMin = 0;
this.strMax = rune.rune_max_attr_adj.getOrDefault(mbEnums.AttributeType.Strength, 0).shortValue();
this.dexStart = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Dexterity, 0).shortValue();
this.dexMin = 0;
this.dexMax = rune.rune_max_attr_adj.getOrDefault(mbEnums.AttributeType.Dexterity, 0).shortValue();
this.conStart = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Constitution, 0).shortValue();
this.conMin = 0;
this.conMax = rune.rune_max_attr_adj.getOrDefault(mbEnums.AttributeType.Constitution, 0).shortValue();
this.intStart = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Intelligence, 0).shortValue();
this.intMin = 0;
this.intMax = rune.rune_max_attr_adj.getOrDefault(mbEnums.AttributeType.Intelligence, 0).shortValue();
this.spiStart = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Spirit, 0).shortValue();
this.spiMin = 0;
this.spiMax = rune.rune_max_attr_adj.getOrDefault(mbEnums.AttributeType.Spirit, 0).shortValue();
this.token = Hasher.SBStringHash(rune.rune_sub_type);
this.healthBonus = (short) rune.rune_health;
this.manaBonus = (short) rune.rune_mana;
this.staminaBonus = (short) rune.rune_stamina;
this.startingPoints = (byte) (STARTING_POINT_POOL - rune.rune_creation_cost);
this.minHeight = dbRace.minHeight;
this.strHeightMod = dbRace.strHeightMod;
this.hairStyles = new HashSet<>(rune.rune_hair);
this.beardStyles = new HashSet<>(rune.rune_beard);
this.skinColors = DbManager.RaceQueries.SKIN_COLOR_FOR_RACE(raceRuneID);
this.beardColors = DbManager.RaceQueries.BEARD_COLORS_FOR_RACE(raceRuneID);
this.hairColors = DbManager.RaceQueries.HAIR_COLORS_FOR_RACE(raceRuneID);
this.baseClasses = getBaseClassesForRace(rune);
this.skillsGranted = SkillReq.getSkillReqsForRune(raceRuneID);
this.powersGranted = PowerReq.getPowerReqsForRune(raceRuneID);
this.effectsList = MobBaseEffects.getEffectsForRune(this.raceRuneID);
// Races without hair styles (Aracoix, Shade) select style 0, which creation validates
if (this.hairStyles.isEmpty())
this.hairStyles.add(0);
}
// Base classes are the creation class runes whose item_race_req names this race's sub type.
// Every creation class rune's race list is a whitelist (restrict false).
private static ArrayList<BaseClass> getBaseClassesForRace(RuneTemplate rune) {
ArrayList<BaseClass> baseClasses = new ArrayList<>();
mbEnums.MonsterType monsterType;
BaseClass baseClass;
monsterType = CacheParserUtil.readEnum(mbEnums.MonsterType.class, rune.rune_sub_type, rune.template_id, "rune_sub_type");
for (RuneTemplate classRune : RuneTemplate._runes.values()) {
if (classRune.rune_type != mbEnums.RuneType.CLASS || !classRune.rune_is_standard_character_creation)
continue;
if (!classRune.item_race_req.contains(monsterType))
continue;
baseClass = DbManager.BaseClassQueries.GET_BASE_CLASS(classRune.template_id);
if (baseClass != null)
baseClasses.add(baseClass);
}
return baseClasses;
}
// Iterates the static_rune_race rows: no rune field separates 2018-2021 from the mob race runes,
// and each row still holds the server-only heights.
public static void loadAllRaces() { public static void loadAllRaces() {
Race._raceByID = DbManager.RaceQueries.LOAD_ALL_RACES();
ConcurrentHashMap<Integer, Race> dbRaces;
ConcurrentHashMap<Integer, Race> races;
RuneTemplate rune;
dbRaces = DbManager.RaceQueries.LOAD_ALL_RACES();
races = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
for (Race dbRace : dbRaces.values()) {
rune = RuneTemplate._runes.get(dbRace.raceRuneID);
if (rune == null || rune.rune_type != mbEnums.RuneType.RACE) {
Logger.warn("Race " + dbRace.raceRuneID + " has no race rune; loaded from static_rune_race");
races.put(dbRace.raceRuneID, dbRace);
continue;
}
races.put(dbRace.raceRuneID, new Race(rune, dbRace));
}
Race._raceByID = races;
Logger.info("Loaded " + races.size() + " races from runes");
} }
public static Race getRace(int id) { public static Race getRace(int id) {
+4 -8
View File
@@ -19,7 +19,6 @@ import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.EnumMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -160,16 +159,13 @@ public class Resists {
private static float[] getArmorResists(Item armor, float[] phys) { private static float[] getArmorResists(Item armor, float[] phys) {
EnumMap<mbEnums.DamageType, Float> armorResists;
if (armor == null) if (armor == null)
return phys; return phys;
if (armor.template.getItemType().equals(mbEnums.ItemType.ARMOR)) { if (armor.template.item_type.equals(mbEnums.ItemType.ARMOR)) {
armorResists = armor.template.getCombatAttackResist(); phys[0] += armor.template.combat_attack_resist.get("SLASHING");
phys[0] += armorResists.getOrDefault(mbEnums.DamageType.SLASHING, 0f); phys[1] += armor.template.combat_attack_resist.get("CRUSHING");
phys[1] += armorResists.getOrDefault(mbEnums.DamageType.CRUSHING, 0f); phys[2] += armor.template.combat_attack_resist.get("PIERCING");
phys[2] += armorResists.getOrDefault(mbEnums.DamageType.PIERCING, 0f);
} }
return phys; return phys;
+4 -224
View File
@@ -12,19 +12,12 @@ package engine.objects;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.mbEnums; import engine.mbEnums;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.parsers.cache.CObjectIndex;
import engine.parsers.objects.RuneTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.util.Hasher;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -32,9 +25,6 @@ public class RuneBase extends AbstractGameObject {
public static HashMap<Integer, ArrayList<Integer>> AllowedBaseClassRunesMap = new HashMap<>(); public static HashMap<Integer, ArrayList<Integer>> AllowedBaseClassRunesMap = new HashMap<>();
public static HashMap<Integer, ArrayList<Integer>> AllowedRaceRunesMap = new HashMap<>(); public static HashMap<Integer, ArrayList<Integer>> AllowedRaceRunesMap = new HashMap<>();
// Flagged rune_is_standard_character_creation but missing from CharCreateRuneList.cfg ATTRRUNES:
// admin runes 2910/2911, unused duplicates, and Proficient with Bows (commented out in the cfg).
private static final Set<Integer> NON_CREATION_TALENTS = new HashSet<>(Arrays.asList(2910, 2911, 250081, 250116, 250117, 250123, 250124, 250125));
private final String name; private final String name;
private final String description; private final String description;
private final int type; private final int type;
@@ -46,12 +36,6 @@ public class RuneBase extends AbstractGameObject {
private final ArrayList<Integer> overwrite = new ArrayList<>(); private final ArrayList<Integer> overwrite = new ArrayList<>();
private int levelRequired = 1; private int levelRequired = 1;
private ArrayList<MobBaseEffects> effectsList = new ArrayList<>(); private ArrayList<MobBaseEffects> effectsList = new ArrayList<>();
private mbEnums.RuneType runeType;
private int subTypeToken;
private int rank;
private boolean raceRestrict;
private boolean classRestrict;
private boolean discRestrict;
/** /**
* No Table ID Constructor * No Table ID Constructor
@@ -90,80 +74,8 @@ public class RuneBase extends AbstractGameObject {
this.type = rs.getInt("type"); this.type = rs.getInt("type");
this.subtype = rs.getByte("subtype"); this.subtype = rs.getByte("subtype");
// static_rune_runereq race/class rows are whitelists, its discipline rows prohibitions
this.discRestrict = true;
DbManager.RuneBaseQueries.GET_RUNE_REQS(this); DbManager.RuneBaseQueries.GET_RUNE_REQS(this);
this.effectsList = MobBaseEffects.getEffectsForRune(this.getObjectUUID()); this.effectsList = DbManager.MobBaseQueries.GET_RUNEBASE_EFFECTS(this.getObjectUUID());
}
/**
* Rune Template Constructor
* type and subtype are server enums that don't map cleanly from rune_type/rune_sub_type, so they
* come from the static_rune_runebase row.
* Talents with the same sub type token replace each other by rank (client 0x4695D0), so no overwrite list.
*/
public RuneBase(RuneTemplate rune, RuneBase dbRuneBase) {
super(rune.template_id);
Integer classRuneID;
Integer discRuneID;
ArrayList<Integer> raceRuneIDs;
RuneTemplate classRune;
this.name = rune.item_base_name;
this.description = rune.rune_dsc;
this.type = dbRuneBase.type;
this.subtype = dbRuneBase.subtype;
this.effectsList = MobBaseEffects.getEffectsForRune(rune.template_id);
this.runeType = rune.rune_type;
this.rank = rune.rune_rank;
this.levelRequired = rune.item_level_req;
this.raceRestrict = rune.item_race_req_restrict;
this.classRestrict = rune.item_class_req_restrict;
this.discRestrict = rune.item_disc_req_restrict;
for (mbEnums.MonsterType raceType : rune.item_race_req) {
raceRuneIDs = CObjectIndex.getRaceRuneIds(raceType);
if (raceRuneIDs.isEmpty())
Logger.warn("RuneBase " + rune.template_id + ": race " + raceType + " has no race rune");
for (int raceRuneID : raceRuneIDs)
this.race.put(raceRuneID, true);
}
for (mbEnums.ClassType classType : rune.item_class_req) {
classRuneID = CObjectIndex.getClassRuneId(classType);
if (classRuneID == null) {
Logger.warn("RuneBase " + rune.template_id + ": class " + classType + " has no class rune");
continue;
}
classRune = RuneTemplate._runes.get(classRuneID);
if (classRune.rune_is_standard_character_creation)
this.baseClass.put(classRuneID, true);
else
this.promotionClass.put(classRuneID, true);
}
for (mbEnums.DisciplineType discType : rune.item_disc_req) {
discRuneID = CObjectIndex.getDisciplineRuneId(discType);
if (discRuneID == null) {
Logger.warn("RuneBase " + rune.template_id + ": discipline " + discType + " has no discipline rune");
continue;
}
this.discipline.put(discRuneID, true);
}
// Same token as CObjectIndex: unresolved sub types are stored as their hash
if (!rune.rune_sub_type.isEmpty())
this.subTypeToken = Hasher.SBStringHash(rune.rune_sub_type);
else
this.subTypeToken = rune.rune_sub_type_hash;
} }
public static RuneBase getRuneBase(int tableId) { public static RuneBase getRuneBase(int tableId) {
@@ -188,117 +100,11 @@ public class RuneBase extends AbstractGameObject {
} }
// Iterates the static_rune_runebase rows: no rune field separates the player runes from the mob
// talents, and each row still holds the server type/subtype.
public static void LoadAllRuneBases() { public static void LoadAllRuneBases() {
ArrayList<RuneBase> dbRuneBases; DbManager.RuneBaseQueries.LOAD_ALL_RUNEBASES();
ArrayList<RuneBaseAttribute> attributes; RuneBase.AllowedBaseClassRunesMap = DbManager.RuneBaseQueries.LOAD_ALLOWED_STARTING_RUNES_FOR_BASECLASS();
RuneTemplate rune; RuneBase.AllowedRaceRunesMap = DbManager.RuneBaseQueries.LOAD_ALLOWED_STARTING_RUNES_FOR_RACE();
int loadedCount = 0;
dbRuneBases = DbManager.RuneBaseQueries.LOAD_ALL_RUNEBASES();
RuneBaseAttribute.runeBaseAttributeMap.clear();
for (RuneBase dbRuneBase : dbRuneBases) {
rune = RuneTemplate._runes.get(dbRuneBase.getObjectUUID());
if (rune == null) {
Logger.warn("RuneBase " + dbRuneBase.getObjectUUID() + " has no rune; loaded from static_rune_runebase without attributes");
continue;
}
DbManager.addToCache(new RuneBase(rune, dbRuneBase));
attributes = RuneBaseAttribute.getAttributesForRune(rune);
// getAttrs() returns null for a rune without attributes, as the DB map did
if (!attributes.isEmpty())
RuneBaseAttribute.runeBaseAttributeMap.put(rune.template_id, attributes);
loadedCount++;
}
Logger.info("Loaded " + loadedCount + " rune bases from runes");
loadCreationTalents();
}
// Every creation race and class gets a list, so the 111111 "any" sentinel of the DB tables is no longer used.
private static void loadCreationTalents() {
ArrayList<Integer> creationRaceIDs = new ArrayList<>();
ArrayList<Integer> creationClassIDs = new ArrayList<>();
ArrayList<Integer> listedRaceIDs;
ArrayList<Integer> listedClassIDs;
Integer classRuneID;
boolean listed;
boolean allowed;
int talentCount = 0;
AllowedRaceRunesMap = new HashMap<>();
AllowedBaseClassRunesMap = new HashMap<>();
for (RuneTemplate rune : RuneTemplate._runes.values()) {
if (!rune.rune_is_standard_character_creation)
continue;
if (rune.rune_type == mbEnums.RuneType.RACE) {
creationRaceIDs.add(rune.template_id);
AllowedRaceRunesMap.put(rune.template_id, new ArrayList<>());
}
if (rune.rune_type == mbEnums.RuneType.CLASS) {
creationClassIDs.add(rune.template_id);
AllowedBaseClassRunesMap.put(rune.template_id, new ArrayList<>());
}
}
for (RuneTemplate rune : RuneTemplate._runes.values()) {
if (!rune.rune_is_standard_character_creation || rune.rune_type != mbEnums.RuneType.TALENT)
continue;
if (NON_CREATION_TALENTS.contains(rune.template_id))
continue;
listedRaceIDs = new ArrayList<>();
listedClassIDs = new ArrayList<>();
for (mbEnums.MonsterType raceType : rune.item_race_req)
listedRaceIDs.addAll(CObjectIndex.getRaceRuneIds(raceType));
for (mbEnums.ClassType classType : rune.item_class_req) {
classRuneID = CObjectIndex.getClassRuneId(classType);
if (classRuneID != null)
listedClassIDs.add(classRuneID);
}
// restrict true = blacklist, false = whitelist (ArcItemRestrict_Check 0x4BAC60)
for (int raceRuneID : creationRaceIDs) {
listed = listedRaceIDs.contains(raceRuneID);
allowed = rune.item_race_req_restrict ? !listed : listed;
if (allowed)
AllowedRaceRunesMap.get(raceRuneID).add(rune.template_id);
}
for (int baseClassID : creationClassIDs) {
listed = listedClassIDs.contains(baseClassID);
allowed = rune.item_class_req_restrict ? !listed : listed;
if (allowed)
AllowedBaseClassRunesMap.get(baseClassID).add(rune.template_id);
}
talentCount++;
}
Logger.info("Loaded " + talentCount + " creation talents for " + creationRaceIDs.size() + " races and "
+ creationClassIDs.size() + " classes from runes");
} }
@Override @Override
@@ -382,32 +188,6 @@ public class RuneBase extends AbstractGameObject {
return this.overwrite; return this.overwrite;
} }
public mbEnums.RuneType getRuneType() {
return this.runeType;
}
// 0 when the rune has no sub type; talents sharing a non-zero token replace each other
public int getSubTypeToken() {
return this.subTypeToken;
}
public int getRank() {
return this.rank;
}
// restrict true: the list is a blacklist; false: a whitelist
public boolean isRaceRestrict() {
return this.raceRestrict;
}
public boolean isClassRestrict() {
return this.classRestrict;
}
public boolean isDiscRestrict() {
return this.discRestrict;
}
/* /*
* Serializing * Serializing
*/ */
-31
View File
@@ -10,15 +10,11 @@
package engine.objects; package engine.objects;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.mbEnums;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.parsers.objects.RuneTemplate;
import engine.server.MBServerStatics;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
@@ -61,33 +57,6 @@ public class RuneBaseAttribute extends AbstractGameObject {
this.runeBaseID = rs.getInt("RuneBaseID"); this.runeBaseID = rs.getInt("RuneBaseID");
} }
// Attribute ids: 0 = rune_creation_cost, 1-5 = rune_attr_adj, 6-10 = rune_max_attr_adj,
// 11-15 = item_attr_req; the AttributeType ordinals Strength..Spirit are 1-5.
public static ArrayList<RuneBaseAttribute> getAttributesForRune(RuneTemplate rune) {
ArrayList<RuneBaseAttribute> attributes = new ArrayList<>();
if (rune.rune_creation_cost != 0)
attributes.add(new RuneBaseAttribute((short) MBServerStatics.RUNE_COST_ATTRIBUTE_ID, (short) rune.rune_creation_cost));
addAttributes(attributes, rune.rune_attr_adj, 0);
addAttributes(attributes, rune.rune_max_attr_adj, 5);
addAttributes(attributes, rune.item_attr_req, 10);
return attributes;
}
private static void addAttributes(ArrayList<RuneBaseAttribute> attributes, EnumMap<mbEnums.AttributeType, Integer> values, int idOffset) {
for (mbEnums.AttributeType attributeType : values.keySet()) {
if (values.get(attributeType) == 0)
continue;
attributes.add(new RuneBaseAttribute((short) (attributeType.ordinal() + idOffset), values.get(attributeType).shortValue()));
}
}
public static void LoadAllAttributes() { public static void LoadAllAttributes() {
DbManager.RuneBaseAttributeQueries.GET_ATTRIBUTES_FOR_RUNEBASE(); DbManager.RuneBaseAttributeQueries.GET_ATTRIBUTES_FOR_RUNEBASE();
+2 -2
View File
@@ -256,13 +256,13 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
if (!boonOwner.charItemManager.doesCharOwnThisItem(boonItem.getObjectUUID())) if (!boonOwner.charItemManager.doesCharOwnThisItem(boonItem.getObjectUUID()))
return false; return false;
for (ShrineType boonShrineType : boonItem.template.getItemOfferingInfo().keySet()) { for (ShrineType boonShrineType : boonItem.template.item_offering_info.keySet()) {
if (boonShrineType != shrineType) if (boonShrineType != shrineType)
continue; continue;
//Same Shrine Type, add favors and stop loop. //Same Shrine Type, add favors and stop loop.
int amount = boonItem.template.getItemOfferingInfo().get(boonShrineType) * boonItem.getNumOfItems(); int amount = boonItem.template.item_offering_info.get(boonShrineType) * boonItem.getNumOfItems();
int oldAmount = this.favors; int oldAmount = this.favors;
if (!DbManager.ShrineQueries.updateFavors(this, this.favors + amount, oldAmount)) { if (!DbManager.ShrineQueries.updateFavors(this, this.favors + amount, oldAmount)) {
-76
View File
@@ -10,27 +10,18 @@
package engine.objects; package engine.objects;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.parsers.objects.RuneTemplate;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class SkillReq extends AbstractGameObject { public class SkillReq extends AbstractGameObject {
private static final int DB_SKILL_REQ_AMOUNT = 80;
private static final ConcurrentHashMap<Integer, ArrayList<SkillReq>> skillReqsByRune = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
private int skillID; private int skillID;
private short level; private short level;
private ArrayList<Byte> skillReqs; private ArrayList<Byte> skillReqs;
private HashMap<Byte, Integer> skillReqAmounts;
/* This shouldn't be used /* This shouldn't be used
public SkillReq(SkillsBase skillsBase, short level, ArrayList<Byte>skillReqs) { public SkillReq(SkillsBase skillsBase, short level, ArrayList<Byte>skillReqs) {
@@ -69,7 +60,6 @@ public class SkillReq extends AbstractGameObject {
this.skillID = rs.getInt("skillID"); this.skillID = rs.getInt("skillID");
this.level = rs.getShort("level"); this.level = rs.getShort("level");
skillReqs = new ArrayList<>(0); skillReqs = new ArrayList<>(0);
skillReqAmounts = new HashMap<>();
int skillReq; int skillReq;
skillReq = rs.getInt("skillreq1"); skillReq = rs.getInt("skillreq1");
@@ -81,68 +71,6 @@ public class SkillReq extends AbstractGameObject {
skillReq = rs.getInt("skillreq3"); skillReq = rs.getInt("skillreq3");
if (skillReq > 0) if (skillReq > 0)
skillReqs.add((byte) skillReq); skillReqs.add((byte) skillReq);
// DB rows carry no amount; the server hard-codes 80
for (byte reqSkillID : skillReqs)
skillReqAmounts.put(reqSkillID, DB_SKILL_REQ_AMOUNT);
}
// skill_value is the level the skill is granted at; skill_granted_skills are prereq skills with amounts
public SkillReq(RuneTemplate.SkillGrant skillGrant, SkillsBase skillsBase, int runeID) {
super();
SkillsBase reqSkillsBase;
this.skillID = skillsBase.getObjectUUID();
this.level = (short) skillGrant.skill_value;
this.skillReqs = new ArrayList<>(0);
this.skillReqAmounts = new HashMap<>();
for (Map.Entry<String, Integer> reqSkill : skillGrant.skill_granted_skills.entrySet()) {
reqSkillsBase = DbManager.SkillsBaseQueries.GET_BASE_BY_NAME(reqSkill.getKey());
if (reqSkillsBase == null) {
Logger.warn("Rune " + runeID + " skill grant " + skillGrant.skill_type + ": unknown prereq skill " + reqSkill.getKey());
continue;
}
this.skillReqs.add((byte) reqSkillsBase.getObjectUUID());
this.skillReqAmounts.put((byte) reqSkillsBase.getObjectUUID(), reqSkill.getValue());
}
}
public static ArrayList<SkillReq> getSkillReqsForRune(int runeID) {
return skillReqsByRune.computeIfAbsent(runeID, SkillReq::loadSkillReqsForRune);
}
private static ArrayList<SkillReq> loadSkillReqsForRune(int runeID) {
ArrayList<SkillReq> runeSkillReqs = new ArrayList<>();
ArrayList<String> skippedGrants = new ArrayList<>();
RuneTemplate rune = RuneTemplate._runes.get(runeID);
SkillsBase skillsBase;
if (rune == null)
return runeSkillReqs;
for (RuneTemplate.SkillGrant skillGrant : rune.rune_skill_grant) {
skillsBase = DbManager.SkillsBaseQueries.GET_BASE_BY_NAME(skillGrant.skill_type);
if (skillsBase == null) {
skippedGrants.add(skillGrant.skill_type);
continue;
}
runeSkillReqs.add(new SkillReq(skillGrant, skillsBase, runeID));
}
// Expected at every boot: Archon 2018 lists resistances as skill grants (Duelist 3010 lists Dueling); not a bug
if (!skippedGrants.isEmpty())
Logger.warn("Rune " + runeID + ": skipped non-skill grants " + skippedGrants);
return runeSkillReqs;
} }
/* /*
@@ -164,10 +92,6 @@ public class SkillReq extends AbstractGameObject {
return this.skillReqs; return this.skillReqs;
} }
public int getSkillReqAmount(byte reqSkillID) {
return this.skillReqAmounts.getOrDefault(reqSkillID, DB_SKILL_REQ_AMOUNT);
}
@Override @Override
public void updateDatabase() { public void updateDatabase() {
-30
View File
@@ -11,16 +11,11 @@ package engine.objects;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.mbEnums.SourceType; import engine.mbEnums.SourceType;
import engine.parsers.objects.RuneTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.util.Hasher;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -107,31 +102,6 @@ public class SkillsBase extends AbstractGameObject {
return null; return null;
} }
// Level 0 adjusts are the skills a rune grants outright; higher levels are trainer caps
public static void LoadAllRuneSkills() {
HashMap<Integer, Integer> grantedSkills;
int entryCount = 0;
for (RuneTemplate rune : RuneTemplate._runes.values()) {
grantedSkills = new HashMap<>();
for (Map.Entry<String, ArrayList<int[]>> skillAdjust : rune.rune_skill_adj.entrySet())
for (int[] adjust : skillAdjust.getValue())
if (adjust[1] == 0)
grantedSkills.put(Hasher.SBStringHash(skillAdjust.getKey()), adjust[0]);
if (grantedSkills.isEmpty())
continue;
runeSkillsCache.put(rune.template_id, grantedSkills);
entryCount += grantedSkills.size();
}
Logger.info("Loaded " + entryCount + " granted skills for " + runeSkillsCache.size() + " runes");
}
public static void putInCache(SkillsBase sb) { public static void putInCache(SkillsBase sb) {
if (sb == null) if (sb == null)
+6 -6
View File
@@ -12,7 +12,7 @@ package engine.objects;
import engine.mbEnums; import engine.mbEnums;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.mbEnums.TransactionType; import engine.mbEnums.TransactionType;
import org.joda.time.DateTime; import java.time.Instant;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -24,7 +24,7 @@ public class Transaction implements Comparable<Transaction> {
private final int warehouseUUID; private final int warehouseUUID;
private final int targetUUID; private final int targetUUID;
private final mbEnums.ResourceType resource; private final mbEnums.ResourceType resource;
private final DateTime date; private final Instant date;
private final int amount; private final int amount;
private final TransactionType transactionType; private final TransactionType transactionType;
private GameObjectType targetType; private GameObjectType targetType;
@@ -41,15 +41,15 @@ public class Transaction implements Comparable<Transaction> {
Date sqlDateTime = rs.getTimestamp("date"); Date sqlDateTime = rs.getTimestamp("date");
if (sqlDateTime != null) if (sqlDateTime != null)
this.date = new DateTime(sqlDateTime); this.date = sqlDateTime.toInstant();
else else
this.date = DateTime.now(); this.date = Instant.now();
} }
public Transaction(int warehouseUUID, GameObjectType targetType, int targetUUID, TransactionType transactionType, mbEnums.ResourceType resource, int amount, public Transaction(int warehouseUUID, GameObjectType targetType, int targetUUID, TransactionType transactionType, mbEnums.ResourceType resource, int amount,
DateTime date) { Instant date) {
this.warehouseUUID = warehouseUUID; this.warehouseUUID = warehouseUUID;
this.targetUUID = targetUUID; this.targetUUID = targetUUID;
this.resource = resource; this.resource = resource;
@@ -75,7 +75,7 @@ public class Transaction implements Comparable<Transaction> {
} }
public DateTime getDate() { public Instant getDate() {
return date; return date;
} }
+9 -13
View File
@@ -17,9 +17,8 @@ import engine.mbEnums;
import engine.net.Dispatch; import engine.net.Dispatch;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.*; import engine.net.client.msg.*;
import engine.parsers.objects.CObjectTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import java.time.Instant;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -32,9 +31,6 @@ import java.util.concurrent.ConcurrentHashMap;
public class Warehouse { public class Warehouse {
// Destroyed warehouses keyed by rubble building UUID; memory only so the rubble can be looted
public static final ConcurrentHashMap<Integer, Warehouse> destroyedWarehouses = new ConcurrentHashMap<>();
public EnumSet<mbEnums.ResourceType> locked = EnumSet.noneOf(mbEnums.ResourceType.class); public EnumSet<mbEnums.ResourceType> locked = EnumSet.noneOf(mbEnums.ResourceType.class);
public Building building; public Building building;
public City city; public City city;
@@ -305,10 +301,10 @@ public class Warehouse {
return false; return false;
} }
if (resource.template.getItemType().equals(mbEnums.ItemType.GOLD)) if (resource.template.item_type.equals(mbEnums.ItemType.GOLD))
resourceType = mbEnums.ResourceType.GOLD; resourceType = mbEnums.ResourceType.GOLD;
else else
resourceType = mbEnums.ResourceType.valueOf(CObjectTemplate.lookup(resource.templateID).getItemBaseName().toUpperCase()); resourceType = mbEnums.ResourceType.valueOf(ItemTemplate.templates.get(resource.templateID).item_base_name.toUpperCase());
if (transaction) if (transaction)
AddTransactionToWarehouse(warehouse, playerCharacter.getObjectType(), playerCharacter.getObjectUUID(), mbEnums.TransactionType.DEPOSIT, resourceType, amount); AddTransactionToWarehouse(warehouse, playerCharacter.getObjectType(), playerCharacter.getObjectUUID(), mbEnums.TransactionType.DEPOSIT, resourceType, amount);
@@ -419,7 +415,7 @@ public class Warehouse {
if (playerCharacter == null) if (playerCharacter == null)
return false; return false;
CObjectTemplate template = CObjectTemplate.lookup(resourceType.templateID); ItemTemplate template = ItemTemplate.templates.get(resourceType.templateID);
if (warehouse.resources.get(resourceType) == null) if (warehouse.resources.get(resourceType) == null)
return false; return false;
@@ -433,7 +429,7 @@ public class Warehouse {
return false; return false;
if (addToInventory) if (addToInventory)
if (!itemMan.hasRoomInventory(template.getItemWt())) { if (!itemMan.hasRoomInventory(template.item_wt)) {
ChatManager.chatSystemInfo(playerCharacter, "You can not carry any more of that item."); ChatManager.chatSystemInfo(playerCharacter, "You can not carry any more of that item.");
return false; return false;
} }
@@ -502,7 +498,7 @@ public class Warehouse {
if (playerCharacter == null) if (playerCharacter == null)
return false; return false;
CObjectTemplate template = CObjectTemplate.lookup(resourceType.templateID); ItemTemplate template = ItemTemplate.templates.get(resourceType);
if (template == null) if (template == null)
return false; return false;
@@ -518,7 +514,7 @@ public class Warehouse {
if (itemMan == null) if (itemMan == null)
return false; return false;
if (!itemMan.hasRoomInventory(template.getItemWt())) { if (!itemMan.hasRoomInventory(template.item_wt)) {
ChatManager.chatSystemInfo(playerCharacter, "You can not carry any more of that item."); ChatManager.chatSystemInfo(playerCharacter, "You can not carry any more of that item.");
return false; return false;
} }
@@ -580,10 +576,10 @@ public class Warehouse {
public static void AddTransactionToWarehouse(Warehouse warehouse, mbEnums.GameObjectType targetType, int targetUUID, mbEnums.TransactionType transactionType, mbEnums.ResourceType resource, int amount) { public static void AddTransactionToWarehouse(Warehouse warehouse, mbEnums.GameObjectType targetType, int targetUUID, mbEnums.TransactionType transactionType, mbEnums.ResourceType resource, int amount) {
if (!DbManager.WarehouseQueries.CREATE_TRANSACTION(warehouse.building.getObjectUUID(), targetType, targetUUID, transactionType, resource, amount, DateTime.now())) if (!DbManager.WarehouseQueries.CREATE_TRANSACTION(warehouse.building.getObjectUUID(), targetType, targetUUID, transactionType, resource, amount, Instant.now()))
return; return;
Transaction transaction = new Transaction(warehouse.building.getObjectUUID(), targetType, targetUUID, transactionType, resource, amount, DateTime.now()); Transaction transaction = new Transaction(warehouse.building.getObjectUUID(), targetType, targetUUID, transactionType, resource, amount, Instant.now());
warehouse.transactions.add(transaction); warehouse.transactions.add(transaction);
} }
-235
View File
@@ -1,235 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.cache;
import engine.mbEnums;
import engine.parsers.objects.CObjectTemplate;
import engine.parsers.objects.DeedTemplate;
import engine.parsers.objects.ItemTemplate;
import engine.parsers.objects.PowerGrant;
import engine.parsers.objects.RuneTemplate;
import engine.parsers.objects.UserPowerAction;
import engine.util.Hasher;
import org.pmw.tinylog.Logger;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
// Lookups across the ITEM, DEED and RUNE cache templates.
// The JSON references runes, skills and powers by name; the server and DB use ids and tokens.
// Build once after all three parsers have loaded. Read only afterwards.
public class CObjectIndex {
private static final EnumMap<mbEnums.MonsterType, ArrayList<Integer>> raceRuneIds = new EnumMap<>(mbEnums.MonsterType.class);
private static final EnumMap<mbEnums.ClassType, Integer> classRuneIds = new EnumMap<>(mbEnums.ClassType.class);
private static final EnumMap<mbEnums.DisciplineType, Integer> disciplineRuneIds = new EnumMap<>(mbEnums.DisciplineType.class);
private static final HashMap<Integer, ArrayList<RuneTemplate>> runesBySubTypeToken = new HashMap<>();
private static final HashMap<String, Integer> skillTokens = new HashMap<>();
private static final HashMap<Integer, String> skillNames = new HashMap<>();
private static final HashMap<String, Integer> powerTokens = new HashMap<>();
private static final HashMap<Integer, String> powerNames = new HashMap<>();
// Same order as the client's id space checks (JSON-Refactor-Plan D1).
public static CObjectTemplate lookup(int templateId) {
CObjectTemplate template;
template = ItemTemplate._items.get(templateId);
if (template == null)
template = DeedTemplate._deeds.get(templateId);
if (template == null)
template = RuneTemplate._runes.get(templateId);
return template;
}
// Male and female runes share a race, so most races return two ids.
public static ArrayList<Integer> getRaceRuneIds(mbEnums.MonsterType race) {
return raceRuneIds.getOrDefault(race, new ArrayList<>());
}
public static Integer getClassRuneId(mbEnums.ClassType classType) {
return classRuneIds.get(classType);
}
public static Integer getDisciplineRuneId(mbEnums.DisciplineType discipline) {
return disciplineRuneIds.get(discipline);
}
// DB race and class tokens are SBStringHash(rune_sub_type). Mob and talent runes share sub types.
public static ArrayList<RuneTemplate> getRunesBySubTypeToken(int token) {
return runesBySubTypeToken.getOrDefault(token, new ArrayList<>());
}
public static Integer getSkillToken(String skillName) {
return skillTokens.get(skillName);
}
public static String getSkillName(int token) {
return skillNames.get(token);
}
public static Integer getPowerToken(String powerName) {
return powerTokens.get(powerName);
}
public static String getPowerName(int token) {
return powerNames.get(token);
}
public static void build() {
int overlapCount = 0;
for (Integer templateId : RuneTemplate._runes.keySet())
if (ItemTemplate._items.containsKey(templateId) || DeedTemplate._deeds.containsKey(templateId))
overlapCount++;
for (Integer templateId : DeedTemplate._deeds.keySet())
if (ItemTemplate._items.containsKey(templateId))
overlapCount++;
if (overlapCount > 0)
Logger.warn(overlapCount + " template ids exist in more than one of ITEM/DEED/RUNE");
for (RuneTemplate rune : RuneTemplate._runes.values()) {
indexRuneName(rune);
indexSubTypeToken(rune);
indexRuneNames(rune);
}
for (ItemTemplate item : ItemTemplate._items.values()) {
addSkill(item.item_skill_used);
addSkill(item.item_skill_mastery_used);
indexItemFields(item.item_skill_req, item.item_user_power_action, item.item_power_grant, item.item_power_action);
}
for (DeedTemplate deed : DeedTemplate._deeds.values()) {
addSkill(deed.item_skill_used);
addSkill(deed.item_skill_mastery_used);
indexItemFields(deed.item_skill_req, deed.item_user_power_action, deed.item_power_grant, deed.item_power_action);
}
Logger.info("Indexed " + raceRuneIds.size() + " races, " + classRuneIds.size() + " classes, "
+ disciplineRuneIds.size() + " disciplines, " + runesBySubTypeToken.size() + " rune sub type tokens, "
+ skillTokens.size() + " skills, " + powerTokens.size() + " powers");
}
private static void indexRuneName(RuneTemplate rune) {
Integer previousId;
if (rune.rune_type == null || rune.rune_sub_type.isEmpty())
return;
try {
switch (rune.rune_type) {
case RACE:
// Mob runes reuse race sub types; only creation races map to player race ids
if (rune.rune_is_standard_character_creation)
raceRuneIds.computeIfAbsent(CacheParserUtil.readEnum(mbEnums.MonsterType.class, rune.rune_sub_type, rune.template_id, "rune_sub_type"),
k -> new ArrayList<>()).add(rune.template_id);
break;
case CLASS:
previousId = classRuneIds.put(CacheParserUtil.readEnum(mbEnums.ClassType.class, rune.rune_sub_type, rune.template_id, "rune_sub_type"), rune.template_id);
if (previousId != null)
Logger.warn(rune.template_id + ": class " + rune.rune_sub_type + " already indexed by " + previousId);
break;
case DISCIPLINE:
previousId = disciplineRuneIds.put(CacheParserUtil.readEnum(mbEnums.DisciplineType.class, rune.rune_sub_type, rune.template_id, "rune_sub_type"), rune.template_id);
if (previousId != null)
Logger.warn(rune.template_id + ": discipline " + rune.rune_sub_type + " already indexed by " + previousId);
break;
default:
break;
}
} catch (IllegalArgumentException e) {
// The Pet class rune has no ClassType
Logger.warn(e.getMessage());
}
}
private static void indexSubTypeToken(RuneTemplate rune) {
int token;
if (!rune.rune_sub_type.isEmpty())
token = Hasher.SBStringHash(rune.rune_sub_type);
else if (rune.rune_sub_type_hash != 0)
token = rune.rune_sub_type_hash;
else
return;
runesBySubTypeToken.computeIfAbsent(token, k -> new ArrayList<>()).add(rune);
}
private static void indexRuneNames(RuneTemplate rune) {
for (RuneTemplate.SkillGrant grant : rune.rune_skill_grant) {
addSkill(grant.skill_type);
grant.skill_granted_skills.keySet().forEach(CObjectIndex::addSkill);
grant.skill_granted_powers.keySet().forEach(CObjectIndex::addPower);
}
rune.rune_skill_adj.keySet().forEach(CObjectIndex::addSkill);
addSkill(rune.item_skill_used);
addSkill(rune.item_skill_mastery_used);
indexItemFields(rune.item_skill_req, rune.item_user_power_action, rune.item_power_grant, rune.item_power_action);
}
private static void indexItemFields(Map<String, Integer> skillReq, ArrayList<UserPowerAction> userPowerActions,
ArrayList<PowerGrant> powerGrants, Map<String, ArrayList<int[]>> powerActions) {
skillReq.keySet().forEach(CObjectIndex::addSkill);
for (UserPowerAction action : userPowerActions)
addPower(action.power);
for (PowerGrant grant : powerGrants) {
addPower(grant.power_type);
grant.power_granted_skills.keySet().forEach(CObjectIndex::addSkill);
grant.power_granted_powers.keySet().forEach(CObjectIndex::addPower);
}
powerActions.keySet().forEach(CObjectIndex::addPower);
}
private static void addSkill(String skillName) {
addName(skillName, skillTokens, skillNames, "skill");
}
private static void addPower(String powerName) {
addName(powerName, powerTokens, powerNames, "power");
}
private static void addName(String name, HashMap<String, Integer> tokens, HashMap<Integer, String> names, String kind) {
int token;
String previousName;
// readHashLabel keeps unresolved hashes as decimal strings; those are not names
if (name == null || name.isEmpty() || name.matches("-?\\d+") || tokens.containsKey(name))
return;
token = Hasher.SBStringHash(name);
tokens.put(name, token);
previousName = names.putIfAbsent(token, name);
if (previousName != null)
Logger.warn(kind + " token " + token + " shared by '" + previousName + "' and '" + name + "'");
}
}
-353
View File
@@ -1,353 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.cache;
import engine.math.Vector3fImmutable;
import engine.parsers.objects.PowerGrant;
import engine.parsers.objects.UserPowerAction;
import org.json.JSONArray;
import org.json.JSONObject;
import org.pmw.tinylog.Logger;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
// Shared JSON helpers for the COBJECTS cache parsers.
// Only generic reading lives here; each parser owns its own field mapping.
public class CacheParserUtil {
// Files are named <template id>.json
public static File[] listJsonFiles(String folderPath) {
File folder = new File(folderPath);
File[] jsonFiles = folder.listFiles((dir, name) -> name.endsWith(".json") && hasTemplateId(name));
if (jsonFiles == null) {
Logger.error("Cache folder not found: " + folder.getAbsolutePath());
return new File[0];
}
return jsonFiles;
}
// Template ids are 32-bit. The client cache has RUNE/10788957847552, which is
// 2512 << 32 (the Huntress id in the high word); files like it are skipped.
private static boolean hasTemplateId(String fileName) {
String idText = fileName.substring(0, fileName.length() - ".json".length());
try {
Integer.parseInt(idText);
return true;
} catch (NumberFormatException e) {
Logger.warn("Skipping " + fileName + ": name is not a 32-bit template id");
return false;
}
}
public static int templateIdFromFile(File jsonFile) {
String fileName = jsonFile.getName();
return Integer.parseInt(fileName.substring(0, fileName.length() - ".json".length()));
}
public static JSONObject readJsonFile(File jsonFile) throws IOException {
byte[] fileData = Files.readAllBytes(jsonFile.toPath());
return new JSONObject(new String(fileData, StandardCharsets.UTF_8));
}
// [x, y, z] -> vector. Returns null for an empty array.
public static Vector3fImmutable readVector3(JSONArray vectorJson) {
if (vectorJson.length() < 3)
return null;
return new Vector3fImmutable(vectorJson.getFloat(0), vectorJson.getFloat(1), vectorJson.getFloat(2));
}
// Client strings carry spaces, hyphens and commas that enum constants
// can't ("Half-Giant", "Battle Magus").
public static String enumName(String value) {
String name = value;
name = name.replaceAll("\\s", "");
name = name.replaceAll("-", "");
name = name.replaceAll(",", "");
return name;
}
// Exact match on the cleaned name first, then upper case (ResourceType).
// Unknown values throw so the template fails to load.
public static <E extends Enum<E>> E readEnum(Class<E> enumClass, String value, int templateId, String fieldName) {
String name = enumName(value);
try {
return Enum.valueOf(enumClass, name);
} catch (IllegalArgumentException e) {
// fall through to upper case
}
try {
return Enum.valueOf(enumClass, name.toUpperCase());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(templateId + ": " + fieldName + " has no " + enumClass.getSimpleName() + " for '" + value + "'");
}
}
public static <E extends Enum<E>> EnumSet<E> readEnumSet(Class<E> enumClass, JSONArray valuesJson, int templateId, String fieldName) {
EnumSet<E> enumSet = EnumSet.noneOf(enumClass);
for (int i = 0; i < valuesJson.length(); i++)
enumSet.add(readEnum(enumClass, valuesJson.getString(i), templateId, fieldName));
return enumSet;
}
// [{keyName: "Strength", valueName: 40}, ...] -> enum map
public static <E extends Enum<E>> EnumMap<E, Integer> readEnumValueMap(Class<E> enumClass, JSONArray entriesJson,
String keyName, String valueName,
int templateId, String fieldName) {
EnumMap<E, Integer> enumMap = new EnumMap<>(enumClass);
JSONObject entry;
for (int i = 0; i < entriesJson.length(); i++) {
entry = entriesJson.getJSONObject(i);
enumMap.put(readEnum(enumClass, entry.getString(keyName), templateId, fieldName), entry.getInt(valueName));
}
return enumMap;
}
// [{keyName: "Sword", valueName: 20}, ...] -> map in file order
public static LinkedHashMap<String, Integer> readStringValueMap(JSONArray entriesJson, String keyName, String valueName) {
LinkedHashMap<String, Integer> valueMap = new LinkedHashMap<>();
JSONObject entry;
for (int i = 0; i < entriesJson.length(); i++) {
entry = entriesJson.getJSONObject(i);
valueMap.put(entry.getString(keyName), (int) entry.getLong(valueName));
}
return valueMap;
}
// {"SLASHING": 0.0, ...} -> enum map
public static <E extends Enum<E>> EnumMap<E, Float> readEnumFloatMap(Class<E> enumClass, JSONObject mapJson,
int templateId, String fieldName) {
EnumMap<E, Float> enumMap = new EnumMap<>(enumClass);
for (String key : mapJson.keySet())
enumMap.put(readEnum(enumClass, key, templateId, fieldName), mapJson.getFloat(key));
return enumMap;
}
// Hash and flag fields are still unsigned in the JSON; read as long and wrapped to int.
public static int[] readIntArray(JSONArray valuesJson) {
int[] values = new int[valuesJson.length()];
for (int i = 0; i < valuesJson.length(); i++)
values[i] = (int) valuesJson.getLong(i);
return values;
}
public static float[] readFloatArray(JSONArray valuesJson) {
float[] values = new float[valuesJson.length()];
for (int i = 0; i < valuesJson.length(); i++)
values[i] = valuesJson.getFloat(i);
return values;
}
public static ArrayList<Integer> readIntList(JSONArray valuesJson) {
ArrayList<Integer> values = new ArrayList<>();
for (int i = 0; i < valuesJson.length(); i++)
values.add((int) valuesJson.getLong(i));
return values;
}
// [[a, b], [a, b], ...] -> list of int[]
public static ArrayList<int[]> readIntArrays(JSONArray arraysJson) {
ArrayList<int[]> arrays = new ArrayList<>();
for (int i = 0; i < arraysJson.length(); i++)
arrays.add(readIntArray(arraysJson.getJSONArray(i)));
return arrays;
}
// Sparse data values are mixed bool/int/string; stored as strings.
public static HashMap<String, String> readSparseData(JSONObject sparseJson) {
HashMap<String, String> sparseData = new HashMap<>();
for (String key : sparseJson.keySet())
sparseData.put(key, sparseJson.get(key).toString());
return sparseData;
}
// Some fields are a name when set and the number 0 when not
// (obj_sound_table, item_skill_used). The number becomes "".
public static String readLabel(JSONObject json, String key) {
Object value = json.get(key);
if (value instanceof String)
return (String) value;
return "";
}
// Like readLabel, but a non-zero number is a hash the exporter could not
// name; it is kept as its decimal string rather than dropped.
public static String readHashLabel(JSONObject json, String key, int templateId) {
Object value = json.get(key);
long hash;
if (value instanceof String)
return (String) value;
hash = json.getLong(key);
if (hash == 0)
return "";
Logger.warn(templateId + ": " + key + " has unresolved hash " + hash);
return Long.toString(hash);
}
public static ArrayList<UserPowerAction> readUserPowerActions(JSONArray actionsJson) {
ArrayList<UserPowerAction> userPowerActions = new ArrayList<>();
JSONObject entry;
for (int i = 0; i < actionsJson.length(); i++) {
entry = actionsJson.getJSONObject(i);
userPowerActions.add(new UserPowerAction(entry.getString("power"), readIntArray(entry.getJSONArray("arguments"))));
}
return userPowerActions;
}
// [[key, value], ...] -> map in file order. Keys are names when the exporter
// knows the hash, otherwise the raw hash, which is kept as its decimal string.
public static LinkedHashMap<String, Integer> readGrantPairs(JSONArray pairsJson, int templateId, String fieldName) {
LinkedHashMap<String, Integer> grantPairs = new LinkedHashMap<>();
JSONArray pair;
Object key;
String keyName;
for (int i = 0; i < pairsJson.length(); i++) {
pair = pairsJson.getJSONArray(i);
key = pair.get(0);
if (key instanceof String) {
keyName = (String) key;
} else {
keyName = Long.toString(pair.getLong(0));
Logger.warn(templateId + ": " + fieldName + " has unresolved hash " + keyName);
}
grantPairs.put(keyName, pair.getInt(1));
}
return grantPairs;
}
public static ArrayList<PowerGrant> readPowerGrants(JSONArray grantsJson, int templateId) {
ArrayList<PowerGrant> powerGrants = new ArrayList<>();
JSONObject entry;
PowerGrant powerGrant;
for (int i = 0; i < grantsJson.length(); i++) {
entry = grantsJson.getJSONObject(i);
powerGrant = new PowerGrant();
powerGrant.power_type = entry.getString("power_type");
powerGrant.power_value = entry.getInt("power_value");
powerGrant.power_granted_attrs.putAll(readGrantPairs(entry.getJSONArray("power_granted_attrs"), templateId, "power_granted_attrs"));
powerGrant.power_granted_skills.putAll(readGrantPairs(entry.getJSONArray("power_granted_skills"), templateId, "power_granted_skills"));
powerGrant.power_granted_powers.putAll(readGrantPairs(entry.getJSONArray("power_granted_powers"), templateId, "power_granted_powers"));
powerGrant.power_monster_types = entry.getJSONArray("power_monster_types");
powerGrants.add(powerGrant);
}
return powerGrants;
}
// [{power_type: "X", power_actions: [{power_arguments: [a, b]}, ...]}, ...]
// -> power_type -> list of argument arrays (one per power_actions entry)
public static LinkedHashMap<String, ArrayList<int[]>> readPowerActions(JSONArray actionsJson) {
LinkedHashMap<String, ArrayList<int[]>> powerActions = new LinkedHashMap<>();
JSONObject entry;
JSONArray argumentsJson;
ArrayList<int[]> arguments;
for (int i = 0; i < actionsJson.length(); i++) {
entry = actionsJson.getJSONObject(i);
argumentsJson = entry.getJSONArray("power_actions");
arguments = new ArrayList<>();
for (int j = 0; j < argumentsJson.length(); j++)
arguments.add(readIntArray(argumentsJson.getJSONObject(j).getJSONArray("power_arguments")));
powerActions.put(entry.getString("power_type"), arguments);
}
return powerActions;
}
}
-186
View File
@@ -1,186 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.cache;
import engine.gameManager.ConfigManager;
import engine.mbEnums;
import engine.parsers.objects.DeedTemplate;
import org.json.JSONArray;
import org.json.JSONObject;
import org.pmw.tinylog.Logger;
import java.io.File;
import java.util.HashMap;
// Loads DEED templates from the client cache JSON (COBJECTS/DEED/<id>.json).
public class DeedParser {
private static final String deedPath = ConfigManager.DEFAULT_DATA_DIR + "COBJECTS/DEED/";
public static HashMap<Integer, DeedTemplate> parseDeedFolder() {
HashMap<Integer, DeedTemplate> deedTemplates = new HashMap<>();
File[] deedFiles = CacheParserUtil.listJsonFiles(deedPath);
int templateId;
JSONObject deedJson;
int failedCount = 0;
for (File deedFile : deedFiles) {
try {
templateId = CacheParserUtil.templateIdFromFile(deedFile);
deedJson = CacheParserUtil.readJsonFile(deedFile);
deedTemplates.put(templateId, parseDeedEntry(templateId, deedJson));
} catch (Exception e) {
Logger.error(deedFile.getName() + ": " + e);
failedCount++;
}
}
Logger.info("Loaded " + deedTemplates.size() + " of " + deedFiles.length + " deed templates");
// Partial deed data is never usable; null tells the caller to abort
if (failedCount > 0)
return null;
return deedTemplates;
}
private static DeedTemplate parseDeedEntry(int templateId, JSONObject deedJson) {
DeedTemplate deed = new DeedTemplate();
JSONObject raceReq;
JSONObject classReq;
JSONObject discReq;
JSONArray itemFlags;
String flag;
deed.template_id = templateId;
// obj_
deed.obj_name = deedJson.getString("obj_name");
deed.obj_pickable = deedJson.getBoolean("obj_pickable");
deed.obj_gravity = deedJson.getFloat("obj_gravity");
deed.obj_cull_distance = deedJson.getFloat("obj_cull_distance");
deed.obj_scale = CacheParserUtil.readVector3(deedJson.getJSONArray("obj_scale"));
deed.obj_render_object = deedJson.getInt("obj_render_object");
deed.obj_double_fusion = deedJson.getBoolean("obj_double_fusion");
deed.obj_forward_vector = CacheParserUtil.readVector3(deedJson.getJSONArray("obj_forward_vector"));
deed.obj_tracking_name = deedJson.getString("obj_tracking_name");
deed.obj_max_tracking_distance = deedJson.getFloat("obj_max_tracking_distance");
deed.obj_icon = deedJson.getInt("obj_icon");
deed.obj_gravity_f = deedJson.getFloat("obj_gravity_f");
deed.obj_sound_events.putAll(CacheParserUtil.readStringValueMap(deedJson.getJSONArray("obj_sound_events"), "sound_type", "sound_event"));
deed.obj_arc_hardpoint_list = deedJson.getJSONArray("obj_arc_hardpoint_list");
deed.obj_sparse_data.putAll(CacheParserUtil.readSparseData(deedJson.getJSONObject("obj_sparse_data")));
deed.obj_render_object_low_detail = deedJson.getInt("obj_render_object_low_detail");
deed.obj_default_alignment = CacheParserUtil.readVector3(deedJson.getJSONArray("obj_default_alignment"));
deed.obj_sound_table = CacheParserUtil.readLabel(deedJson, "obj_sound_table");
// combat_
deed.combat_health_current = deedJson.getFloat("combat_health_current");
deed.combat_health_full = deedJson.getFloat("combat_health_full");
deed.combat_attack_resist.putAll(CacheParserUtil.readEnumFloatMap(mbEnums.DamageType.class, deedJson.getJSONObject("combat_attack_resist"),
templateId, "combat_attack_resist"));
deed.combat_powers = deedJson.getJSONArray("combat_powers");
// item_
deed.item_type = CacheParserUtil.readEnum(mbEnums.ItemType.class, deedJson.getString("item_type"), templateId, "item_type");
deed.item_eq_slots_value = deedJson.getInt("item_eq_slots_value");
deed.item_eq_slots_type = deedJson.getBoolean("item_eq_slots_type");
// The exporter writes ["NONE"] for an empty slot mask
deed.item_eq_slots_or.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, deedJson.getJSONArray("item_eq_slots_or"), templateId, "item_eq_slots_or"));
deed.item_eq_slots_or.remove(mbEnums.EquipSlotType.NONE);
deed.item_eq_slots_and.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, deedJson.getJSONArray("item_eq_slots_and"), templateId, "item_eq_slots_and"));
deed.item_eq_slots_and.remove(mbEnums.EquipSlotType.NONE);
deed.item_takeable = deedJson.getBoolean("item_takeable");
deed.item_value = deedJson.getInt("item_value");
deed.item_wt = deedJson.getInt("item_wt");
deed.item_passive_defense_mod = deedJson.getFloat("item_passive_defense_mod");
deed.item_base_name = deedJson.getString("item_base_name");
deed.item_dsc = deedJson.getString("item_dsc");
deed.item_render_object_female = deedJson.getInt("item_render_object_female");
deed.item_health_full = deedJson.getFloat("item_health_full");
deed.item_skill_used = CacheParserUtil.readLabel(deedJson, "item_skill_used");
deed.item_skill_mastery_used = CacheParserUtil.readLabel(deedJson, "item_skill_mastery_used");
deed.item_parry_anim_id = deedJson.getInt("item_parry_anim_id");
deed.item_offering_info.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, deedJson.getJSONArray("item_offering_info"),
"offering_type", "offering_value", templateId, "item_offering_info"));
// "None" is the client's empty marker, not a flag
itemFlags = deedJson.getJSONArray("item_flags");
for (int i = 0; i < itemFlags.length(); i++) {
flag = itemFlags.getString(i);
if (flag.equals("None"))
continue;
deed.item_flags.add(CacheParserUtil.readEnum(mbEnums.ItemFlags.class, flag, templateId, "item_flags"));
}
deed.item_use_flags.addAll(CacheParserUtil.readEnumSet(mbEnums.ItemUseFlags.class, deedJson.getJSONArray("item_use_flags"), templateId, "item_use_flags"));
deed.item_post_item_id = deedJson.getInt("item_post_item_id");
deed.item_initial_charges = deedJson.getInt("item_initial_charges");
deed.item_book_arcana = deedJson.getInt("item_book_arcana");
deed.item_skill_req.putAll(CacheParserUtil.readStringValueMap(deedJson.getJSONArray("item_skill_req"), "skill_type", "skill_level"));
raceReq = deedJson.getJSONObject("item_race_req");
deed.item_race_req_restrict = raceReq.getBoolean("restrict");
deed.item_race_req.addAll(CacheParserUtil.readEnumSet(mbEnums.MonsterType.class, raceReq.getJSONArray("races"), templateId, "item_race_req"));
classReq = deedJson.getJSONObject("item_class_req");
deed.item_class_req_restrict = classReq.getBoolean("restrict");
deed.item_class_req.addAll(CacheParserUtil.readEnumSet(mbEnums.ClassType.class, classReq.getJSONArray("classes"), templateId, "item_class_req"));
discReq = deedJson.getJSONObject("item_disc_req");
deed.item_disc_req_restrict = discReq.getBoolean("restrict");
deed.item_disc_req.addAll(CacheParserUtil.readEnumSet(mbEnums.DisciplineType.class, discReq.getJSONArray("discs"), templateId, "item_disc_req"));
deed.item_attr_req.putAll(CacheParserUtil.readEnumValueMap(mbEnums.AttributeType.class, deedJson.getJSONArray("item_attr_req"),
"attr_type", "attr_value", templateId, "item_attr_req"));
deed.item_level_req = deedJson.getInt("item_level_req");
deed.item_rank_req = deedJson.getInt("item_rank_req");
deed.item_sex_req = CacheParserUtil.readEnum(mbEnums.SexType.class, deedJson.getString("item_sex_req"), templateId, "item_sex_req");
deed.item_user_power_action.addAll(CacheParserUtil.readUserPowerActions(deedJson.getJSONArray("item_user_power_action")));
deed.item_power_grant.addAll(CacheParserUtil.readPowerGrants(deedJson.getJSONArray("item_power_grant"), templateId));
deed.item_power_action.putAll(CacheParserUtil.readPowerActions(deedJson.getJSONArray("item_power_action")));
deed.item_sheathable = deedJson.getBoolean("item_sheathable");
deed.item_has_stub = deedJson.getBoolean("item_has_stub");
deed.item_offering_adjustments.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, deedJson.getJSONArray("item_offering_adjustments"),
"offering_type", "offering_value", templateId, "item_offering_adjustments"));
deed.item_resource_costs.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ResourceType.class, deedJson.getJSONArray("item_resource_costs"),
"resource_type", "resource_value", templateId, "item_resource_costs"));
deed.item_bane_rank = deedJson.getInt("item_bane_rank");
deed.item_ignore_saved_actions = deedJson.getBoolean("item_ignore_saved_actions");
// deed_
deed.deed_type = deedJson.getInt("deed_type");
deed.deed_furniture_id = deedJson.getInt("deed_furniture_id");
deed.deed_target_id = deedJson.getInt("deed_target_id");
deed.deed_employment = deedJson.getInt("deed_employment");
deed.deed_start_rank = deedJson.getInt("deed_start_rank");
deed.deed_name_lookup = deedJson.getInt("deed_name_lookup");
deed.deed_indoors = deedJson.getBoolean("deed_indoors");
deed.deed_is_fortress = deedJson.getBoolean("deed_is_fortress");
deed.deed_namelookup_val = deedJson.getFloat("deed_namelookup_val");
deed.deed_custom_city = deedJson.getBoolean("deed_custom_city");
deed.deed_structure_id = deedJson.getInt("deed_structure_id");
return deed;
}
}
Loaded 100 of 153 files, more files were not shown because too many files have changed in this diff. Show more