/*********************************************************************************** * Copyright (c) 2015 /// Project SWG /// www.projectswg.com * * * * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * * Our goal is to create an emulator which will provide a server for players to * * continue playing a game similar to the one they used to play. We are basing * * it on the final publish of the game prior to end-game events. * * * * This file is part of Holocore. * * * * -------------------------------------------------------------------------------- * * * * Holocore is free software: you can redistribute it and/or modify * * it under the terms of the GNU Affero General Public License as * * published by the Free Software Foundation, either version 3 of the * * License, or (at your option) any later version. * * * * Holocore is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Affero General Public License for more details. * * * * You should have received a copy of the GNU Affero General Public License * * along with Holocore. If not, see . * * * ***********************************************************************************/ package resources.objects.creature; import java.util.List; import network.packets.swg.zone.SceneEndBaselines; import network.packets.swg.zone.UpdatePostureMessage; import network.packets.swg.zone.UpdatePvpStatusMessage; import network.packets.swg.zone.baselines.Baseline.BaselineType; import resources.HologramColour; import resources.Posture; import resources.Race; import resources.collections.SWGList; import resources.collections.SWGMap; import resources.encodables.player.Equipment; import resources.network.BaselineBuilder; import resources.objects.SWGObject; import resources.objects.player.PlayerObject; import resources.objects.tangible.TangibleObject; import resources.objects.weapon.WeaponObject; import resources.player.Player; import utilities.Encoder.StringType; public class CreatureObject extends TangibleObject { private static final long serialVersionUID = 1L; private Posture posture = Posture.UPRIGHT; private Race race = Race.HUMAN; private double movementScale = 1; private double movementPercent = 1; private double walkSpeed = 1.549; private double runSpeed = 7.3; private double accelScale = 1; private double accelPercent = 1; private double turnScale = 1; private double slopeModAngle = 1; private double slopeModPercent = 1; private double waterModPercent = 0.75; private double height = 0; private long performanceListenTarget = 0; private int guildId = 0; private short level = 1; private int levelHealthGranted = 0; private int totalLevelXp = 0; private CreatureDifficulty difficulty = CreatureDifficulty.NORMAL; private int cashBalance = 0; private int bankBalance = 0; private String moodAnimation = "neutral"; private String animation = ""; private long equippedWeaponId = 0; private byte moodId = 0; private long lookAtTargetId = 0; private long intendedTargetId = 0; private int performanceCounter = 0; private int performanceId = 0; private String costume = ""; private boolean visible = true; private boolean performing = false; private boolean shownOnRadar = true; private boolean beast = false; private long groupId = 0; private byte factionRank = 0; private long ownerId = 0; private int battleFatigue = 0; private long statesBitmask = 0; private HologramColour hologramColour = HologramColour.DEFAULT; private SWGList baseAttributes = new SWGList(BaselineType.CREO, 1, 2); private SWGList skills = new SWGList(BaselineType.CREO, 1, 3, false, StringType.ASCII); private SWGList hamEncumbList = new SWGList(BaselineType.CREO, 4, 2, true); private SWGList attributes = new SWGList(BaselineType.CREO, 6, 21, true); private SWGList maxAttributes = new SWGList(BaselineType.CREO, 6, 22, true); private SWGList equipmentList = new SWGList(BaselineType.CREO, 6, 23); private SWGList appearanceList = new SWGList(BaselineType.CREO, 6, 33); private SWGMap skillMods = new SWGMap<>(BaselineType.CREO, 4, 3, StringType.ASCII); // TODO: SkillMod structure private SWGMap missionCriticalObjs = new SWGMap<>(BaselineType.CREO, 4, 13); private SWGMap abilities = new SWGMap<>(BaselineType.CREO, 4, 14, StringType.ASCII); private SWGMap buffs = new SWGMap<>(BaselineType.CREO, 6, 26); // TODO: Buff structure public CreatureObject(long objectId) { super(objectId); initMaxAttributes(); initCurrentAttributes(); initBaseAttributes(); } /** * It is only recommended that this method be used when you have * an item and you won't know which slots it will occupy until you've * looped through the arrangement list that resides within SWGObject. * * If you know the slot which your object is supposed to occupy, it's * recommended that you instead use setSlot(), effectively skipping * the process of looping. * * @param item to equip */ public void equipItem(TangibleObject item) { equipItemToContainer(item, this); } public void equipAppearanceItem(TangibleObject item) { equipItemToContainer(item, super.getSlottedObject("appearance_inventory")); } public void unequipAppearanceItem(TangibleObject item) { unequipItemFromContainer(item, super.getSlottedObject("appearance_inventory")); } private void equipItemToContainer(TangibleObject item, SWGObject container) { for(List slotNameList : item.getArrangement()) for(String slotName : slotNameList) container.setSlot(slotName, item); } private void unequipItemFromContainer(TangibleObject item, SWGObject container) { for(List slotNameList : item.getArrangement()) for(String slotName : slotNameList) container.setSlot(slotName, null); } public void removeEquipment(SWGObject obj) { synchronized (equipmentList) { if (equipmentList.remove(obj)) equipmentList.sendDeltaMessage(this); } } public void addEquipment(SWGObject obj) { synchronized(equipmentList) { if (obj instanceof WeaponObject) equipmentList.add(new Equipment((WeaponObject) obj)); else equipmentList.add(new Equipment(obj.getObjectId(), obj.getTemplate())); equipmentList.sendDeltaMessage(this); } } public void addAppearanceItem(SWGObject obj) { synchronized(appearanceList) { appearanceList.add(new Equipment(obj.getObjectId(), obj.getTemplate())); appearanceList.sendDeltaMessage(this); } } public SWGList getEquipmentList() { return equipmentList; } public SWGList getAppearanceList() { return appearanceList; } public SWGList getSkills() { return skills; } public int getCashBalance() { return cashBalance; } public int getBankBalance() { return bankBalance; } public Posture getPosture() { return posture; } public Race getRace() { return race; } public double getMovementScale() { return movementScale; } public double getMovementPercent() { return movementPercent; } public double getWalkSpeed() { return walkSpeed; } public double getRunSpeed() { return runSpeed; } public double getAccelScale() { return accelScale; } public double getAccelPercent() { return accelPercent; } public double getTurnScale() { return turnScale; } public double getSlopeModAngle() { return slopeModAngle; } public double getSlopeModPercent() { return slopeModPercent; } public double getWaterModPercent() { return waterModPercent; } public double getHeight() { return height; } public long getPerformanceListenTarget() { return performanceListenTarget; } public int getGuildId() { return guildId; } public int getLevel() { return level; } public int getLevelHealthGranted() { return levelHealthGranted; } public int getTotalLevelXp() { return totalLevelXp; } public CreatureDifficulty getDifficulty() { return difficulty; } public PlayerObject getPlayerObject() { return (PlayerObject) (hasSlot("ghost") ? getSlottedObject("ghost") : null); } public void setPosture(Posture posture) { this.posture = posture; sendDelta(3, 13, posture.getId()); } public void setRace(Race race) { this.race = race; } public void setCashBalance(int cashBalance) { this.cashBalance = cashBalance; sendDelta(1, 0, cashBalance); } public void setBankBalance(int bankBalance) { this.bankBalance = bankBalance; sendDelta(1, 1, bankBalance); } public void setMovementScale(double movementScale) { this.movementScale = movementScale; sendDelta(4, 4, movementScale); } public void setMovementPercent(double movementPercent) { this.movementPercent = movementPercent; sendDelta(4, 5, movementPercent); } public void setWalkSpeed(double walkSpeed) { this.walkSpeed = walkSpeed; sendDelta(4, 11, walkSpeed); } public void setRunSpeed(double runSpeed) { this.runSpeed = runSpeed; sendDelta(4, 7, runSpeed); } public void setAccelScale(double accelScale) { this.accelScale = accelScale; sendDelta(4, 0, accelScale); } public void setAccelPercent(double accelPercent) { this.accelPercent = accelPercent; sendDelta(4, 1, accelPercent); } public void setTurnScale(double turnScale) { this.turnScale = turnScale; sendDelta(4, 10, turnScale); } public void setSlopeModAngle(double slopeModAngle) { this.slopeModAngle = slopeModAngle; sendDelta(4, 8, slopeModAngle); } public void setSlopeModPercent(double slopeModPercent) { this.slopeModPercent = slopeModPercent; sendDelta(4, 9, slopeModPercent); } public void setWaterModPercent(double waterModPercent) { this.waterModPercent = waterModPercent; sendDelta(4, 12, waterModPercent); } public void setHeight(double height) { this.height = height; sendDelta(3, 16, height); } public void setPerformanceListenTarget(long performanceListenTarget) { this.performanceListenTarget = performanceListenTarget; sendDelta(4, 6, performanceListenTarget); } public void setGuildId(int guildId) { this.guildId = guildId; sendDelta(6, 15, guildId); } public void setLevel(short level) { this.level = level; sendDelta(6, 8, level); } public void setLevelHealthGranted(int levelHealthGranted) { this.levelHealthGranted = levelHealthGranted; sendDelta(6, 9, levelHealthGranted); } public void setTotalLevelXp(int totalLevelXp) { this.totalLevelXp = totalLevelXp; sendDelta(4, 15, totalLevelXp); } public void setDifficulty(CreatureDifficulty difficulty) { this.difficulty = difficulty; sendDelta(6, 26, difficulty.getDifficulty()); } public String getMoodAnimation() { return moodAnimation; } public void setMoodAnimation(String moodAnimation) { this.moodAnimation = moodAnimation; sendDelta(6, 11, moodAnimation, StringType.ASCII); } public boolean isBeast() { return beast; } public void setBeast(boolean beast) { this.beast = beast; sendDelta(6, 31, beast); } public String getAnimation() { return animation; } public void setAnimation(String animation) { this.animation = animation; sendDelta(6, 10, animation, StringType.ASCII); } public long getEquippedWeaponId() { return equippedWeaponId; } public void setEquippedWeaponId(long equippedWeaponId) { this.equippedWeaponId = equippedWeaponId; sendDelta(6, 12, equippedWeaponId); } public byte getMoodId() { return moodId; } public void setMoodId(byte moodId) { this.moodId = moodId; sendDelta(6, 18, moodId); } public long getLookAtTargetId() { return lookAtTargetId; } public void setLookAtTargetId(long lookAtTargetId) { this.lookAtTargetId = lookAtTargetId; sendDelta(6, 16, lookAtTargetId); } public long getIntendedTargetId() { return intendedTargetId; } public void setIntendedTargetId(long intendedTargetId) { this.intendedTargetId = intendedTargetId; sendDelta(6, 17, intendedTargetId); } public int getPerformanceCounter() { return performanceCounter; } public void setPerformanceCounter(int performanceCounter) { this.performanceCounter = performanceCounter; sendDelta(6, 19, performanceCounter); } public int getPerformanceId() { return performanceId; } public void setPerformanceId(int performanceId) { this.performanceId = performanceId; sendDelta(6, 20, performanceId); } public String getCostume() { return costume; } public void setCostume(String costume) { this.costume = costume; sendDelta(6, 24, costume, StringType.ASCII); } public long getGroupId() { return groupId; } public void setGroupId(long groupId) { this.groupId = groupId; sendDelta(6, 13, groupId); } public byte getFactionRank() { return factionRank; } public void setFactionRank(byte factionRank) { this.factionRank = factionRank; sendDelta(3, 14, factionRank); } public long getOwnerId() { return ownerId; } public void setOwnerId(long ownerId) { this.ownerId = ownerId; sendDelta(3, 15, ownerId); } public int getBattleFatigue() { return battleFatigue; } public void setBattleFatigue(int battleFatigue) { this.battleFatigue = battleFatigue; sendDelta(3, 17, battleFatigue); } public long getStatesBitmask() { return statesBitmask; } public void setStatesBitmask(long statesBitmask) { this.statesBitmask = statesBitmask; sendDelta(3, 18, statesBitmask); } public boolean isVisible() { return visible; } public void setVisible(boolean visible) { this.visible = visible; sendDelta(6, 25, visible); } public boolean isPerforming() { return performing; } public void setPerforming(boolean performing) { this.performing = performing; sendDelta(6, 27, performing); } public void setHologramColour(HologramColour hologramColour) { this.hologramColour = hologramColour; sendDelta(6, 29, hologramColour.getValue()); } public boolean isShownOnRadar() { return shownOnRadar; } public void setShownOnRadar(boolean shownOnRadar) { this.shownOnRadar = shownOnRadar; sendDelta(6, 30, shownOnRadar); } public int getHealth() { return attributes.get(0); } public int getMaxHealth() { return maxAttributes.get(0); } public int getBaseHealth() { return baseAttributes.get(0); } public int getAction() { return attributes.get(2); } public int getMaxAction() { return attributes.get(2); } public int getBaseAction() { return attributes.get(2); } public void setHealth(int health) { synchronized(attributes) { attributes.set(0, health); attributes.sendDeltaMessage(this); } } public void setMaxHealth(int maxHealth) { synchronized(maxAttributes) { maxAttributes.set(0, maxHealth); maxAttributes.sendDeltaMessage(this); } } public void setAction(int action) { synchronized(attributes) { attributes.set(2, action); attributes.sendDeltaMessage(this); } } public void setMaxAction(int maxAction) { synchronized(maxAttributes) { maxAttributes.set(2, maxAction); maxAttributes.sendDeltaMessage(this); } } private void initMaxAttributes() { maxAttributes.add(0, 1000); // Health maxAttributes.add(1, 0); maxAttributes.add(2, 300); // Action maxAttributes.add(3, 0); maxAttributes.add(4, 300); // ?? maxAttributes.add(5, 0); maxAttributes.clearDeltaQueue(); } private void initCurrentAttributes() { attributes.add(0, 1000); // Health attributes.add(1, 0); attributes.add(2, 300); // Action attributes.add(3, 0); attributes.add(4, 300); // ?? attributes.add(5, 0); attributes.clearDeltaQueue(); } private void initBaseAttributes() { baseAttributes.add(0, 1000); // Health baseAttributes.add(1, 0); baseAttributes.add(2, 300); // Action baseAttributes.add(3, 0); baseAttributes.add(4, 300); // ?? baseAttributes.add(5, 0); baseAttributes.clearDeltaQueue(); } @Override public boolean equals(Object obj) { return super.equals(obj); } @Override public int hashCode() { return (super.hashCode() * 7 + posture.getId()) * 13 + race.toString().hashCode(); } public void createObject(Player target) { sendSceneCreateObject(target); BaselineBuilder bb = null; if (getOwner() == target) { bb = new BaselineBuilder(this, BaselineType.CREO, 1); createBaseline1(target, bb); bb.sendTo(target); } bb = new BaselineBuilder(this, BaselineType.CREO, 3); createBaseline3(target, bb); bb.sendTo(target); if (getOwner() == target) { bb = new BaselineBuilder(this, BaselineType.CREO, 4); createBaseline4(target, bb); bb.sendTo(target); } bb = new BaselineBuilder(this, BaselineType.CREO, 6); createBaseline6(target, bb); bb.sendTo(target); if (getOwner() == target) { bb = new BaselineBuilder(this, BaselineType.CREO, 8); createBaseline8(target, bb); bb.sendTo(target); bb = new BaselineBuilder(this, BaselineType.CREO, 9); createBaseline9(target, bb); bb.sendTo(target); } createChildrenObjects(target); target.sendPacket(new SceneEndBaselines(getObjectId())); } protected void createChildrenObjects(Player target) { target.sendPacket(new UpdatePostureMessage(posture.getId(), getObjectId())); if (target != getOwner()) target.sendPacket(new UpdatePvpStatusMessage(UpdatePvpStatusMessage.PLAYER, 0, getObjectId())); // TODO: Change this when adding non-players super.createChildrenObjects(target); } public void createBaseline1(Player target, BaselineBuilder bb) { super.createBaseline1(target, bb); // 0 variables bb.addInt(cashBalance); // 0 bb.addInt(bankBalance); // 1 bb.addObject(baseAttributes); // Attributes player has without any gear on -- 2 bb.addObject(skills); // 3 bb.incrementOperandCount(4); } public void createBaseline3(Player target, BaselineBuilder bb) { super.createBaseline3(target, bb); // 13 variables - TANO3 (9) + BASE3 (4) bb.addByte(posture.getId()); // 13 bb.addByte(factionRank); // 14 bb.addLong(ownerId); // 15 bb.addFloat((float) height); // 16 bb.addInt(battleFatigue); // 17 bb.addLong(statesBitmask); // 18 bb.incrementOperandCount(6); } public void createBaseline4(Player target, BaselineBuilder bb) { super.createBaseline4(target, bb); // 0 variables bb.addFloat((float) accelScale); // 0 bb.addFloat((float) accelPercent); // 1 bb.addObject(hamEncumbList); // 2 bb.addObject(skillMods); // 3 bb.addFloat((float) movementScale); // 4 bb.addFloat((float) movementPercent); // 5 bb.addLong(performanceListenTarget); // 6 bb.addFloat((float) runSpeed); // 7 bb.addFloat((float) slopeModAngle); // 8 bb.addFloat((float) slopeModPercent); // 9 bb.addFloat((float) turnScale); // 10 bb.addFloat((float) walkSpeed); // 11 bb.addFloat((float) waterModPercent); // 12 bb.addObject(missionCriticalObjs); // 13 bb.addObject(abilities); // 14 bb.addInt(totalLevelXp); // 15 bb.incrementOperandCount(16); } public void createBaseline6(Player target, BaselineBuilder bb) { super.createBaseline6(target, bb); // 8 variables - TANO6 (6) + BASE6 (2) bb.addShort(level); // 8 bb.addInt(levelHealthGranted); // 9 bb.addAscii(animation); // 10 bb.addAscii(moodAnimation); // 11 bb.addLong(equippedWeaponId); // 12 bb.addLong(groupId); // 13 bb.addLong(0); // Group Inviter ID -- 14 bb.addAscii(""); // Group Inviter Name bb.addLong(0); // Invite counter bb.addInt(guildId); // 15 bb.addLong(lookAtTargetId); // 16 bb.addLong(intendedTargetId); // 17 bb.addByte(moodId); // 18 bb.addInt(performanceCounter); // 19 bb.addInt(performanceId); // 20 bb.addObject(attributes); // 21 bb.addObject(maxAttributes); // 22 bb.addObject(equipmentList); // 23 bb.addAscii(costume); // 24 bb.addBoolean(visible); // 25 bb.addObject(buffs); // 26 bb.addBoolean(performing); // 27 bb.addByte(difficulty.getDifficulty()); // 28 bb.addInt((hologramColour == null) ? -1 : hologramColour.getValue()); // Hologram Color -- 29 bb.addBoolean(shownOnRadar); // 30 bb.addBoolean(beast); // 31 bb.addByte(0); // Unknown -- 32 bb.addObject(appearanceList); // 33 bb.addLong(0); // unknown -- 34 bb.incrementOperandCount(27); } public void createBaseline8(Player target, BaselineBuilder bb) { super.createBaseline8(target, bb); } public void createBaseline9(Player target, BaselineBuilder bb) { super.createBaseline9(target, bb); } public void sendDelta(int type, int update, Object value) { sendDelta(BaselineType.CREO, type, update, value); } public void sendDelta(int type, int update, Object value, StringType strType) { sendDelta(BaselineType.CREO, type, update, value, strType); } }