This commit is contained in:
Waverunner
2014-03-29 16:48:01 -04:00
14 changed files with 270 additions and 48 deletions
+9 -3
View File
@@ -31,6 +31,11 @@ def run(core, actor, target, commandString):
actor.setFaction('')
actor.sendSystemMessage('@faction_recruiter:resign_complete', 0)
if commandString == 'neutral' or commandString == 'resign':
time.sleep(1)
actor.setFaction('')
actor.sendSystemMessage('@faction_recruiter:resign_complete', 0)
return
time.sleep(1)
actor.setFaction(commandString)
@@ -46,8 +51,8 @@ def run(core, actor, target, commandString):
time.sleep(1)
actor.setFactionStatus(FactionStatus.Combatant)
actor.setPvpStatus(PvpStatus.GoingCovert, False)
actor.setPvpStatus(PvpStatus.Enemy, True)
actor.sendSystemMessage('@faction_recruiter:covert_complete', 0)
actor.updatePvpStatus()
return
if factionStatus == FactionStatus.Combatant:
@@ -56,8 +61,8 @@ def run(core, actor, target, commandString):
time.sleep(30)
actor.setFactionStatus(FactionStatus.SpecialForces)
actor.setPvpStatus(PvpStatus.GoingOvert, False)
actor.setPvpStatus(PvpStatus.Overt | PvpStatus.Attackable | PvpStatus.Aggressive, True)
actor.sendSystemMessage('@faction_recruiter:overt_complete', 0)
actor.updatePvpStatus()
return
if factionStatus == FactionStatus.SpecialForces:
@@ -65,8 +70,9 @@ def run(core, actor, target, commandString):
actor.setPvpStatus(PvpStatus.GoingCovert, True)
time.sleep(300)
actor.setFactionStatus(FactionStatus.Combatant)
actor.setPvpStatus(PvpStatus.GoingCovert | PvpStatus.Overt | PvpStatus.Attackable | PvpStatus.Aggressive, False)
actor.setPvpStatus(PvpStatus.GoingCovert, False)
actor.sendSystemMessage('@faction_recruiter:covert_complete', 0)
actor.updatePvpStatus()
return
return
+23
View File
@@ -0,0 +1,23 @@
import sys
def chest2():
return "35.71"
def pants1():
return "21.43"
def hat():
return "14.27"
def bracer_upper_l():
return "7.15"
def bracer_upper_r():
return "7.15"
def bicep_l():
return "7.15"
def bicep_r():
return "7.15"
@@ -458,7 +458,7 @@ public class CreatureObject extends TangibleObject implements IPersistent {
}
notifyObservers(messageBuilder.buildFactionDelta(faction), true);
setPvpStatus(0, true);
//updatePvpStatus();
}
public int getFactionStatus() {
@@ -473,6 +473,7 @@ public class CreatureObject extends TangibleObject implements IPersistent {
}
notifyObservers(messageBuilder.buildFactionStatusDelta(factionStatus), true);
//updatePvpStatus();
}
public float getHeight() {
@@ -22,10 +22,14 @@
package resources.objects.tangible;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import main.NGECore;
import protocol.swg.ObjControllerMessage;
import protocol.swg.PlayClientEffectObjectMessage;
import protocol.swg.StopClientEffectObjectByLabel;
@@ -58,7 +62,7 @@ public class TangibleObject extends SWGObject {
protected int optionsBitmask = 0;
private int maxDamage = 1000;
private boolean staticObject = true;
protected String faction = "neutral"; // Says you're "Imperial Special Forces" if it's 0 for some reason
protected String faction = ""; // Says you're "Imperial Special Forces" if it's 0 for some reason
@NotPersistent
private Vector<TangibleObject> defendersList = new Vector<TangibleObject>(); // unused in packets but useful for the server
@NotPersistent
@@ -218,6 +222,23 @@ public class TangibleObject extends SWGObject {
}
}
}
//updatePvpStatus();
}
public void updatePvpStatus() {
HashSet<Client> observers = new HashSet<Client>(getObservers());
for (Iterator<Client> it = observers.iterator(); it.hasNext();) {
Client observer = it.next();
if (observer.getParent() != null) {
observer.getSession().write(new UpdatePVPStatusMessage(this.getObjectID(), NGECore.getInstance().factionService.calculatePvpStatus((CreatureObject) observer.getParent(), this), getFaction()).serialize());
if(getClient() != null)
getClient().getSession().write(new UpdatePVPStatusMessage(observer.getParent().getObjectID(), NGECore.getInstance().factionService.calculatePvpStatus((CreatureObject) this, (CreatureObject) observer.getParent()), getFaction()).serialize());
}
}
}
public String getFaction() {
@@ -230,6 +251,8 @@ public class TangibleObject extends SWGObject {
synchronized(objectMutex) {
this.faction = faction;
}
updatePvpStatus();
}
public Vector<TangibleObject> getDefendersList() {
+1 -1
View File
@@ -210,7 +210,7 @@ public class ConnectionService implements INetworkDispatch {
object.setSpectatorTask(null);
}
//core.groupService.handleGroupDisband(object); // Seefo: Temporarily moved to simulationService.handleDisconnect as a temporary fix for issue #295
core.groupService.handleGroupDisband(object);
if (core.instanceService.isInInstance(object)) {
core.instanceService.remove(core.instanceService.getActiveInstance(object), object);
+45 -6
View File
@@ -56,7 +56,7 @@ public class EquipmentService implements INetworkDispatch {
private int getWeaponCriticalChance(CreatureObject actor, SWGObject item) {
int weaponCriticalChance = 0;
String weaponCriticalSkillMod = (core.scriptService.getMethod("scripts/equipment/", "weapon_critical", item.getStringAttribute("cat_wpn_damage.wpn_category")/*.replace(" ", "").replace("-", "") + "_" */).__call__().asString());
String weaponCriticalSkillMod = (core.scriptService.getMethod("scripts/equipment/", "weapon_critical", item.getStringAttribute("cat_wpn_damage.wpn_category")).__call__().asString());
if(weaponCriticalSkillMod.contains(" "))
weaponCriticalSkillMod.replace(" ", "");
@@ -65,7 +65,7 @@ public class EquipmentService implements INetworkDispatch {
weaponCriticalSkillMod.replace("-", "");
if(actor.getSkillMod(weaponCriticalSkillMod) != null)
weaponCriticalChance = actor.getSkillModBase((core.scriptService.getMethod("scripts/equipment/", "weapon_critical", item.getStringAttribute("cat_wpn_damage.wpn_category").replace(" ", "").replace("-", "") + "_" ).__call__().asString()));
weaponCriticalChance = actor.getSkillModBase(weaponCriticalSkillMod);
return weaponCriticalChance;
}
@@ -132,12 +132,34 @@ public class EquipmentService implements INetworkDispatch {
return result;
}
private float calculateArmorProtection (float protection, String slotName) {
return protection *= (Float.parseFloat(core.scriptService.getMethod("scripts/equipment/", "slot_protection", slotName).__call__().asString()) / 100);
}
private void addArmorProtection(CreatureObject actor, String protectionType, float protection, String slotName) {
actor.addSkillMod(protectionType, (int) (calculateArmorProtection(protection, slotName)));
}
private void deductArmorProtection(CreatureObject actor, String protectionType, float protection, String slotName) {
actor.deductSkillMod(protectionType, (int) calculateArmorProtection(protection, slotName));
}
private void addForceProtection(CreatureObject actor, SWGObject item) {
actor.addSkillMod("expertise_innate_protection_all", getForceProtection(item));
actor.addSkillMod("kinetic", getForceProtection(item));
actor.addSkillMod("energy", getForceProtection(item));
actor.addSkillMod("heat", getForceProtection(item));
actor.addSkillMod("cold", getForceProtection(item));
actor.addSkillMod("acid", getForceProtection(item));
actor.addSkillMod("electricity", getForceProtection(item));
}
private void deductForceProtection(CreatureObject actor, SWGObject item) {
actor.deductSkillMod("expertise_innate_protection_all", getForceProtection(item));
actor.deductSkillMod("kinetic", getForceProtection(item));
actor.deductSkillMod("energy", getForceProtection(item));
actor.deductSkillMod("heat", getForceProtection(item));
actor.deductSkillMod("cold", getForceProtection(item));
actor.deductSkillMod("acid", getForceProtection(item));
actor.deductSkillMod("electricity", getForceProtection(item));
}
private int getForceProtection(SWGObject item) {
@@ -163,8 +185,7 @@ public class EquipmentService implements INetworkDispatch {
// TODO: bio-link (assign it by objectID with setAttachment and then just display the customName for that objectID).
if(item.getStringAttribute("cat_wpn_damage.wpn_category") != null)
if (actor.getSlotNameForObject(item).contentEquals("hold_r") == true)
addWeaponCriticalChance(actor, item);
addWeaponCriticalChance(actor, item);
Map<String, Object> attributes = new TreeMap<String, Object>(item.getAttributes());
@@ -177,6 +198,14 @@ public class EquipmentService implements INetworkDispatch {
core.skillModService.addSkillMod(actor, e.getKey().replace("cat_stat_mod_bonus.@stat_n:", ""), Integer.parseInt((String) e.getValue()));
}
if(e.getKey().startsWith("cat_armor_standard_protection")) {
addArmorProtection(actor, e.getKey().replace("cat_armor_standard_protection.armor_eff_", ""), Float.parseFloat((String) e.getValue()), actor.getSlotNameForObject(item));
}
if(e.getKey().startsWith("cat_armor_special_protection")) {
addArmorProtection(actor, e.getKey().replace("cat_armor_special_protection.special_protection_type_", ""), Float.parseFloat((String) e.getValue()), actor.getSlotNameForObject(item));
}
if(e.getKey().startsWith("cat_attrib_mod_bonus.attr_health")) {
actor.setMaxHealth(actor.getMaxHealth() + Integer.parseInt((String) e.getValue()));
}
@@ -184,6 +213,7 @@ public class EquipmentService implements INetworkDispatch {
if(e.getKey().startsWith("cat_attrib_mod_bonus.attr_action")) {
actor.setMaxAction(actor.getMaxAction() + Integer.parseInt((String) e.getValue()));
}
}
if(!actor.getEquipmentList().contains(item))
@@ -215,6 +245,15 @@ public class EquipmentService implements INetworkDispatch {
if(e.getKey().startsWith("cat_stat_mod_bonus.@stat_n:")) {
core.skillModService.deductSkillMod(actor, e.getKey().replace("cat_stat_mod_bonus.@stat_n:", ""), Integer.parseInt((String) e.getValue()));
}
if(e.getKey().startsWith("cat_armor_standard_protection")) {
deductArmorProtection(actor, e.getKey().replace("cat_armor_standard_protection.armor_eff_", ""), Float.parseFloat((String) e.getValue()), actor.getSlotNameForObject(item));
}
if(e.getKey().startsWith("cat_armor_special_protection")) {
deductArmorProtection(actor, e.getKey().replace("cat_armor_special_protection.special_protection_type_", ""), Float.parseFloat((String) e.getValue()), actor.getSlotNameForObject(item));
}
if(e.getKey().startsWith("cat_attrib_mod_bonus.attr_health")) {
actor.setMaxHealth(actor.getMaxHealth() - Integer.parseInt((String) e.getValue()));
}
+6 -5
View File
@@ -75,6 +75,7 @@ import protocol.swg.objectControllerObjects.TargetUpdate;
import resources.objects.building.BuildingObject;
import resources.objects.cell.CellObject;
import resources.objects.creature.CreatureObject;
import resources.objects.group.GroupObject;
import resources.objects.player.PlayerObject;
import resources.objects.tangible.TangibleObject;
import resources.common.*;
@@ -755,8 +756,6 @@ public class SimulationService implements INetworkDispatch {
}
}
core.groupService.handleGroupDisband(object); // Seefo: Temporarily moved from connectionService.disconnect as a temporary fix for issue #295
/*
object.createTransaction(core.getCreatureODB().getEnvironment());
core.getCreatureODB().put(object, Long.class, CreatureObject.class, object.getTransaction());
@@ -812,6 +811,10 @@ public class SimulationService implements INetworkDispatch {
object.playMusic("sound/music_acq_bountyhunter.snd");
core.skillService.addSkill(object, ghost.getProfessionWheelPosition());
}
if(object.getGroupId() != 0 && core.objectService.getObject(object.getGroupId()) instanceof GroupObject)
object.makeAware(core.objectService.getObject(object.getGroupId()));
}
public void transferToPlanet(SWGObject object, Planet planet, Point3D newPos, Quaternion newOrientation, SWGObject newParent) {
@@ -844,9 +847,7 @@ public class SimulationService implements INetworkDispatch {
synchronized(object.getMutex()) {
object.getAwareObjects().removeAll(object.getAwareObjects());
}
object.setPlanet(planet);
@@ -872,7 +873,7 @@ public class SimulationService implements INetworkDispatch {
if(container.getPermissions().canView(requester, container)) {
OpenedContainerMessage opm = new OpenedContainerMessage(container.getObjectID());
if(requester.getClient() != null && requester.getClient().getSession() != null)
if(requester.getClient() != null && requester.getClient().getSession() != null && !(container instanceof CreatureObject))
requester.getClient().getSession().write(opm.serialize());
}
+44 -2
View File
@@ -30,7 +30,6 @@ import org.python.core.Py;
import org.python.core.PyObject;
import protocol.swg.ExpertiseRequestMessage;
import resources.common.Console;
import resources.common.FileUtilities;
import resources.common.Opcodes;
@@ -303,7 +302,7 @@ public class SkillService implements INetworkDispatch {
return;
for(String expertiseName : expertise.getExpertiseSkills()) {
if(expertiseName.startsWith("expertise_") && ((caluclateExpertisePoints(creature) - 1) >= 0)) { // Prevent possible glitches/exploits
if(expertiseName.startsWith("expertise_") && ((caluclateExpertisePoints(creature) - 1) >= 0) && validExpertiseSkill(player, expertiseName)) { // Prevent possible glitches/exploits
addSkill(creature, expertiseName);
}
}
@@ -325,6 +324,49 @@ public class SkillService implements INetworkDispatch {
return expertisePoints;
}
public boolean validExpertiseSkill(PlayerObject player, String skill)
{
try
{
DatatableVisitor table = ClientFileManager.loadFile("datatables/expertise/expertise.iff", DatatableVisitor.class);
String profession;
switch(player.getProfession())
{
case "trader_0a":
profession = "trader_dom";
break;
case "trader_0b":
profession = "trader_struct";
break;
case "trader_0c":
profession = "trader_mun";
break;
case "trader_0d":
profession = "trader_eng";
break;
default:
profession = player.getProfession().replace("_1a", "");
break;
}
for (int s = 0; s < table.getRowCount(); s++)
{
if (table.getObject(s, 0) != null && ((String) table.getObject(s, 0)).equals(skill))
{
if(((String)table.getObject(s, 7)).equals(profession) || ((String)table.getObject(s, 7)).equals("all")) return true;
else return false;
}
}
}
catch (Exception e) { e.printStackTrace(); }
return false;
}
@Override
public void shutdown() {
+24 -9
View File
@@ -30,7 +30,6 @@ import java.util.concurrent.TimeUnit;
import main.NGECore;
import net.engio.mbassy.listener.Handler;
import engine.resources.objects.SWGObject;
import engine.resources.scene.Point3D;
import engine.resources.scene.Quaternion;
@@ -120,12 +119,16 @@ public class AIActor {
}
public void setCurrentState(AIState currentState) {
if(currentState.getClass() == this.currentState.getClass())
return;
if(this.currentState != null)
doStateAction(this.currentState.onExit(this));
this.currentState = currentState;
doStateAction(currentState.onEnter(this));
try {
if(currentState.getClass() == this.currentState.getClass())
return;
if(this.currentState != null)
doStateAction(this.currentState.onExit(this));
this.currentState = currentState;
doStateAction(currentState.onEnter(this));
} catch (Exception e) {
e.printStackTrace();
}
}
public CreatureObject getFollowObject() {
@@ -153,11 +156,23 @@ public class AIActor {
}
public void scheduleMovement() {
scheduler.schedule(() -> doStateAction(currentState.move(AIActor.this)), 500, TimeUnit.MILLISECONDS);
scheduler.schedule(() -> {
try {
doStateAction(currentState.move(AIActor.this));
} catch (Exception e) {
e.printStackTrace();
}
}, 500, TimeUnit.MILLISECONDS);
}
public void scheduleRecovery() {
scheduler.schedule(() -> doStateAction(currentState.recover(AIActor.this)), 2000, TimeUnit.MILLISECONDS);
scheduler.schedule(() -> {
try {
doStateAction(currentState.recover(AIActor.this));
} catch (Exception e) {
e.printStackTrace();
}
}, 2000, TimeUnit.MILLISECONDS);
}
public void setNextPosition(Point3D position) {
+4 -4
View File
@@ -34,10 +34,10 @@ import services.ai.AIActor;
public abstract class AIState {
public abstract byte onEnter(AIActor actor);
public abstract byte onExit(AIActor actor);
public abstract byte move(AIActor actor);
public abstract byte recover(AIActor actor);
public abstract byte onEnter(AIActor actor) throws Exception;
public abstract byte onExit(AIActor actor) throws Exception;
public abstract byte move(AIActor actor) throws Exception;
public abstract byte recover(AIActor actor) throws Exception;
public enum StateResult {;
+18 -8
View File
@@ -264,7 +264,7 @@ public class CombatService implements INetworkDispatch {
sendCombatPackets(attacker, target, weapon, command, actionCounter, damage, 0, HitType.HIT);
if(FileUtilities.doesFileExist("scripts/commands/combat/" + command.getCommandName() + ".py"))
core.scriptService.callScript("scripts/commands/combat/", command.getCommandName(), "run", core, attacker, target, null);
core.scriptService.callScript("scripts/commands/combat/", command.getCommandName(), "run", core, attacker, target, damage);
}
@@ -379,7 +379,7 @@ public class CombatService implements INetworkDispatch {
}
if(FileUtilities.doesFileExist("scripts/commands/combat/" + command.getCommandName() + ".py"))
core.scriptService.callScript("scripts/commands/combat/", command.getCommandName(), "run", core, attacker, target, null);
core.scriptService.callScript("scripts/commands/combat/", command.getCommandName(), "run", core, attacker, target, damage);
return;
@@ -812,6 +812,14 @@ public class CombatService implements INetworkDispatch {
target.getEventBus().publish(event);
}
@SuppressWarnings("unused")
public void doDrainHeal(CreatureObject receiver, int drainAmount) {
synchronized(receiver.getMutex()) {
receiver.setHealth(receiver.getHealth() + drainAmount);
}
}
private boolean isInConeAngle(CreatureObject attacker, SWGObject target, int coneLength, int coneWidth, float directionX, float directionZ) {
float radius = coneWidth / 2;
@@ -830,7 +838,7 @@ public class CombatService implements INetworkDispatch {
return true;
}
}
public boolean attemptHeal(CreatureObject healer, CreatureObject target) {
@@ -847,6 +855,8 @@ public class CombatService implements INetworkDispatch {
return false;
}
if(target.getAttachment("AI") != null) return false;
if(healer.getFaction().equals(target.getFaction())) {
if(healer.getFactionStatus() < target.getFactionStatus())
@@ -997,8 +1007,8 @@ public class CombatService implements INetworkDispatch {
requester.getDuelList().add(target);
requester.sendSystemMessage("You accept " + target.getCustomName() + "'s challenge.", (byte) 0);
target.sendSystemMessage(requester.getCustomName() + " accepts your challenge.", (byte) 0);
target.getClient().getSession().write(new UpdatePVPStatusMessage(requester.getObjectID(), 55, requester.getFaction()).serialize());
requester.getClient().getSession().write(new UpdatePVPStatusMessage(target.getObjectID(), 55, target.getFaction()).serialize());
target.updatePvpStatus();
requester.updatePvpStatus();
}
@@ -1013,8 +1023,8 @@ public class CombatService implements INetworkDispatch {
target.removeDefender(requester);
requester.removeDefender(target);
target.getClient().getSession().write(new UpdatePVPStatusMessage(requester.getObjectID(), 0x16, requester.getFaction()).serialize());
requester.getClient().getSession().write(new UpdatePVPStatusMessage(target.getObjectID(), 0x16, target.getFaction()).serialize());
target.updatePvpStatus();
requester.updatePvpStatus();
if(announce)
{
@@ -1032,7 +1042,7 @@ public class CombatService implements INetworkDispatch {
success = false;
if((command.getAttackType() == 0 || command.getAttackType() == 1 || command.getAttackType() == 3) && !attemptHeal(medic, target))
target = medic;
success = false;
if(!success) {
IoSession session = medic.getClient().getSession();
+47 -7
View File
@@ -198,23 +198,42 @@ public class FactionService implements INetworkDispatch {
* This should be used instead of getPvPBitmask where possible, but
* should not be used in setPvPBitmask.
*/
public int calculatePvpStatus(CreatureObject player, TangibleObject target) {
/*public int calculatePvpStatus(CreatureObject player, TangibleObject target) {
PlayerObject ghost = (PlayerObject) player.getSlottedObject("ghost");
int pvpBitmask = target.getPvPBitmask();
if (target.getSlottedObject("ghost") != null) {
if (target.getFaction() == null || (!target.getFaction().equals("rebel") && !target.getFaction().equals("imperial"))) {
return 0;
}
// Seefo: Casting target to type CreatureObject as temporary fix. I am unsure whether or not we want to put a factionStatus member inside of TangibleObject.
if (((CreatureObject) target).getFactionStatus() == FactionStatus.Combatant) {
pvpBitmask |= PvpStatus.Enemy;
}
if (((CreatureObject) target).getFactionStatus() == FactionStatus.SpecialForces) {
pvpBitmask |= PvpStatus.Overt;
if (target.getSlottedObject("ghost") != null) {
pvpBitmask |= PvpStatus.Enemy;
}
}
if (target.getSlottedObject("ghost") != null) {
pvpBitmask |= PvpStatus.Player;
if (player.getFactionStatus() == FactionStatus.SpecialForces &&
((CreatureObject) target).getFactionStatus() == FactionStatus.SpecialForces) {
if ((!player.getFaction().equals(target.getFaction()) &&
player.getFactionStatus() == FactionStatus.SpecialForces &&
((CreatureObject) target).getFactionStatus() == FactionStatus.SpecialForces) ||
core.combatService.areInDuel(player, (CreatureObject) target)) {
pvpBitmask |= (PvpStatus.Attackable | PvpStatus.Aggressive);
}
if (core.combatService.areInDuel(player, (CreatureObject) target)) {
//pvpBitmask |= PvpStatus.Dueling;
}
return pvpBitmask;
}
if (player.getFaction().equals(target.getFaction())) {
return pvpBitmask;
}
@@ -235,6 +254,27 @@ public class FactionService implements INetworkDispatch {
}
return pvpBitmask;
}*/
// temp fix until calculatePvpStatus is fixed
public int calculatePvpStatus(CreatureObject player, TangibleObject target) {
if(target.getSlottedObject("ghost") != null) {
if(!player.getFaction().equals(target.getFaction()) && player.getFactionStatus() == FactionStatus.SpecialForces && ((CreatureObject) target).getFactionStatus() == FactionStatus.SpecialForces)
return 55;
else if(core.combatService.areInDuel(player, (CreatureObject) target))
return 55;
else
return 0x14;
} else {
if(target.getAttachment("AI") != null)
return PvpStatus.Attackable;
else
return 0;
}
}
public Map<String, Integer> getFactionMap() {
+21
View File
@@ -1,3 +1,24 @@
/*******************************************************************************
* Copyright (c) 2013 <Project SWG>
*
* This File is part of NGECore2.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Using NGEngine to work with NGECore2 is making a combined work based on NGEngine.
* Therefore all terms and conditions of the GNU Lesser General Public License cover the combination.
******************************************************************************/
package services.object;
import com.sleepycat.persist.model.Entity;
+2 -1
View File
@@ -25,6 +25,7 @@ import resources.objects.creature.CreatureObject;
import engine.clients.Client;
import engine.resources.container.AllPermissions;
import engine.resources.container.CreatureContainerPermissions;
import engine.resources.container.CreaturePermissions;
import engine.resources.objects.SWGObject;
import engine.resources.service.INetworkDispatch;
import engine.resources.service.INetworkRemoteEvent;
@@ -205,7 +206,7 @@ public class TradeService implements INetworkDispatch{
}
else {
if(objectToTrade.getAttributes().containsKey("no_trade")) {
if(objectToTrade.getAttributes().containsKey("no_trade") || !objectToTrade.getPermissions().canRemove(client.getParent(), objectToTrade.getContainer()) || (objectToTrade.getContainer() instanceof CreatureObject)) {
return;
}