package net.scapeemulator.game.model.player;
import static net.scapeemulator.game.model.player.skills.prayer.Prayer.HEAL;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import java.util.ArrayList;
import java.util.List;
import net.scapeemulator.game.GameServer;
import net.scapeemulator.game.model.Position;
import net.scapeemulator.game.model.World;
import net.scapeemulator.game.model.definition.NPCDefinitions;
import net.scapeemulator.game.model.grounditem.GroundItemSynchronizer;
import net.scapeemulator.game.model.mob.Animation;
import net.scapeemulator.game.model.mob.Mob;
import net.scapeemulator.game.model.mob.combat.AttackType;
import net.scapeemulator.game.model.mob.combat.CombatBonuses;
import net.scapeemulator.game.model.npc.NPC;
import net.scapeemulator.game.model.object.GroundObjectSynchronizer;
import net.scapeemulator.game.model.player.PlayerVariables.Variable;
import net.scapeemulator.game.model.player.action.PlayerDeathAction;
import net.scapeemulator.game.model.player.appearance.Appearance;
import net.scapeemulator.game.model.player.bank.BankSession;
import net.scapeemulator.game.model.player.bank.BankSettings;
import net.scapeemulator.game.model.player.interfaces.AccessSet;
import net.scapeemulator.game.model.player.interfaces.InterfaceSet;
import net.scapeemulator.game.model.player.inventory.Inventory;
import net.scapeemulator.game.model.player.skills.Skill;
import net.scapeemulator.game.model.player.skills.SkillAppearanceListener;
import net.scapeemulator.game.model.player.skills.SkillMessageListener;
import net.scapeemulator.game.model.player.skills.SkillSet;
import net.scapeemulator.game.model.player.skills.construction.House;
import net.scapeemulator.game.model.player.skills.farming.PlayerFarms;
import net.scapeemulator.game.model.player.skills.firemaking.Firemaking;
import net.scapeemulator.game.model.player.skills.fishing.FishingTool;
import net.scapeemulator.game.model.player.skills.magic.Rune;
import net.scapeemulator.game.model.player.skills.magic.Spellbook;
import net.scapeemulator.game.model.player.skills.mining.Pickaxe;
import net.scapeemulator.game.model.player.skills.prayer.Prayers;
import net.scapeemulator.game.model.player.skills.ranged.Arrow;
import net.scapeemulator.game.model.player.skills.ranged.Bow;
import net.scapeemulator.game.model.player.skills.woodcutting.Hatchet;
import net.scapeemulator.game.model.player.trade.TradeSession;
import net.scapeemulator.game.msg.Message;
import net.scapeemulator.game.msg.impl.ChatMessage;
import net.scapeemulator.game.msg.impl.EnergyMessage;
import net.scapeemulator.game.msg.impl.LogoutMessage;
import net.scapeemulator.game.msg.impl.PlayerMenuOptionMessage;
import net.scapeemulator.game.msg.impl.ServerMessage;
import net.scapeemulator.game.msg.impl.inter.InterfaceTextMessage;
import net.scapeemulator.game.net.game.GameSession;
import net.scapeemulator.game.task.Task;
import net.scapeemulator.game.util.StringUtils;
import net.scapeemulator.util.Base37Utils;
public final class Player extends Mob {
private static final Position[] HOME_LOCATIONS = {new Position(3222, 3222)};
private static int appearanceTicketCounter = 0;
private static Animation DEATH_ANIMATION = new Animation(7185, 50);
private static int nextAppearanceTicket() {
if (++appearanceTicketCounter == 0) {
appearanceTicketCounter = 1;
}
return appearanceTicketCounter;
}
private int databaseId;
private String username;
private String displayName;
private long longUsername;
private String password;
private int rights = 0;
private GameSession session;
private boolean regionChanging;
private boolean updateModelLists;
private boolean blockActions;
private Position lastKnownRegion = position;
private final List<Player> localPlayers = new ArrayList<>();
private final List<NPC> localNpcs = new ArrayList<>();
private Appearance appearance = new Appearance(this);
private ForcedMovement forcedMove;
private int energy = 100;
private Player wantToTrade;
private TradeSession tradeSession;
private final House house = new House(this);
private House inHouse;
private final PlayerFarms farms = new PlayerFarms(this);
private final SkillSet skillSet = new SkillSet();
private BankSession bankSession;
private final BankSettings bankSettings = new BankSettings();
private final InventorySet inventorySet = new InventorySet(this);
private ChatMessage chatMessage;
private RegionPalette constructedRegion;
private SceneRebuiltListener sceneRebuiltListener;
private final PlayerTimers timers = new PlayerTimers();
private final Friends friends = new Friends(this);
private final Prayers prayers = new Prayers(this);
private final ScriptInput scriptInput = new ScriptInput(this);
private final PlayerSettings settings = new PlayerSettings(this);
private final PlayerVariables variables = new PlayerVariables();
private final InterfaceSet interfaceSet = new InterfaceSet(this);
private final GrandExchangeHandler grandExchangeHandler = new GrandExchangeHandler(this);
private final ShopHandler shopHandler = new ShopHandler(this);
private final StateSet stateSet = new StateSet(this);
private Spellbook spellbook = Spellbook.NORMAL_SPELLBOOK;
private final AccessSet accessSet = new AccessSet(this);
private final GroundItemSynchronizer groundItemSync = new GroundItemSynchronizer(this);
private final GroundObjectSynchronizer groundObjSync = new GroundObjectSynchronizer(this);
private int[] appearanceTickets = new int[World.MAX_PLAYERS];
private int appearanceTicket = nextAppearanceTicket();
private final PlayerOption[] options = new PlayerOption[10];
private int pnpc = -1;
public Player() {
init();
}
public boolean actionsBlocked() {
return blockActions || !alive();
}
private String addPlus(int bonus) {
return bonus > 0 ? "+" + bonus : "" + bonus;
}
public void appearanceUpdated() {
appearanceTicket = nextAppearanceTicket();
}
public void calculateEquipmentBonuses() {
for (AttackType type : AttackType.values()) {
int typeAttackBonus = 0;
int typeDefenceBonus = 0;
for (Item equipped : getEquipment().toArray()) {
if (equipped == null) {
continue;
}
typeAttackBonus += equipped.getEquipmentDefinition().getBonuses().getAttackBonus(type);
typeDefenceBonus += equipped.getEquipmentDefinition().getBonuses().getDefenceBonus(type);
}
combatBonuses.setAttackBonus(type, typeAttackBonus);
combatBonuses.setDefenceBonus(type, typeDefenceBonus);
}
int prayerBonus = 0;
int strengthBonus = 0;
for (Item equipped : getEquipment().toArray()) {
if (equipped == null) {
continue;
}
prayerBonus += equipped.getEquipmentDefinition().getBonuses().getPrayerBonus();
strengthBonus += equipped.getEquipmentDefinition().getBonuses().getStrengthBonus();
}
combatBonuses.setPrayerBonus(prayerBonus);
combatBonuses.setStrengthBonus(strengthBonus);
Item weapon = getEquipment().get(Equipment.WEAPON);
Item ammo = getEquipment().get(Equipment.AMMO);
int rangeBonus = weapon == null ? 0 : weapon.getEquipmentDefinition().getBonuses().getRangeStrengthBonus();
if (rangeBonus == 0 && ammo != null) {
rangeBonus = ammo.getEquipmentDefinition().getBonuses().getRangeStrengthBonus();
}
combatBonuses.setRangeStrengthBonus(rangeBonus);
if (getInterfaceSet().getWindow().getCurrentId() == 667) {
sendEquipmentBonuses();
}
}
public void endBankSession() {
bankSession = null;
}
public AccessSet getAccessSet() {
return accessSet;
}
public Appearance getAppearance() {
return appearance;
}
public int getAppearanceTicket() {
return appearanceTicket;
}
public int[] getAppearanceTickets() {
return appearanceTickets;
}
public Inventory getBank() {
return inventorySet.getBank();
}
public BankSession getBankSession() {
return bankSession;
}
public BankSettings getBankSettings() {
return bankSettings;
}
public ChatMessage getChatMessage() {
return chatMessage;
}
@Override
public int getCurrentHitpoints() {
return skillSet.getCurrentLevel(Skill.HITPOINTS);
}
public int getDatabaseId() {
return databaseId;
}
public Animation getDeathAnimation() {
return DEATH_ANIMATION;
}
public String getDisplayName() {
return displayName;
}
public int getEnergy() {
return energy;
}
public Inventory getEquipment() {
return inventorySet.getEquipment();
}
public Friends getFriends() {
return friends;
}
public PlayerTimers getTimers() {
return timers;
}
public GrandExchangeHandler getGrandExchangeHandler() {
return grandExchangeHandler;
}
@Override
public int getHealthRegen() {
int regen = prayers.prayerActive(HEAL) ? 2 : 1;
// Regen brace
if (getEquipment().get(Equipment.HANDS) != null) {
regen += getEquipment().get(Equipment.HANDS).getId() == 11133 ? 1 : 0;
}
return regen;
}
public Position getHomeLocation() {
return HOME_LOCATIONS[variables.getVar(Variable.HOME_LOCATION)];
}
public InterfaceSet getInterfaceSet() {
return interfaceSet;
}
public Inventory getInventory() {
return inventorySet.getInventory();
}
public InventorySet getInventorySet() {
return inventorySet;
}
public Position getLastKnownRegion() {
return lastKnownRegion;
}
public List<NPC> getLocalNpcs() {
return localNpcs;
}
public List<Player> getLocalPlayers() {
return localPlayers;
}
public long getLongUsername() {
return longUsername;
}
@Override
public int getMaximumHitpoints() {
return skillSet.getLevel(Skill.HITPOINTS);
}
public PlayerOption getOption(int id) {
return options[id];
}
public String getPassword() {
return password;
}
public PlayerCombatHandler getPlayerCombatHandler() {
return (PlayerCombatHandler) combatHandler;
}
public int getPNPC() {
return pnpc;
}
public int getPrayerPoints() {
return skillSet.getCurrentLevel(Skill.PRAYER);
}
public Prayers getPrayers() {
return prayers;
}
public int getRights() {
return rights;
}
public ScriptInput getScriptInput() {
return scriptInput;
}
public GameSession getSession() {
return session;
}
public PlayerSettings getSettings() {
return settings;
}
public PlayerVariables getVariables() {
return variables;
}
public ShopHandler getShopHandler() {
return shopHandler;
}
public House getHouse() {
return house;
}
public House getInHouse() {
return inHouse;
}
public void setInHouse(House inHouse) {
this.inHouse = inHouse;
}
public PlayerFarms getFarms() {
return farms;
}
public SkillSet getSkillSet() {
return skillSet;
}
public Spellbook getSpellbook() {
return spellbook;
}
public int getStance() {
if (pnpc > -1) {
return NPCDefinitions.forId(pnpc).getStance();
}
Item weapon = inventorySet.getEquipment().get(Equipment.WEAPON);
if (weapon != null) {
return EquipmentDefinition.forId(weapon.getId()).getStance();
} else {
return 1426;
}
}
public StateSet getStateSet() {
return stateSet;
}
public int getTotalWeight() {
return getInventory().getWeight() + getEquipment().getWeight();
}
public TradeSession getTradeSession() {
return tradeSession;
}
public boolean getUpdateModelLists() {
return updateModelLists;
}
public String getUsername() {
return username;
}
@Override
public void heal(int amount) {
int temp = getCurrentHitpoints() + amount;
temp = temp > getMaximumHitpoints() ? getMaximumHitpoints() : temp;
skillSet.setCurrentLevel(Skill.HITPOINTS, temp);
}
private void init() {
combatBonuses = new CombatBonuses();
combatHandler = new PlayerCombatHandler(this);
skillSet.addListener(new SkillMessageListener(this));
skillSet.addListener(new SkillAppearanceListener(this));
World.getWorld().getGroundObjects().addListener(groundObjSync);
World.getWorld().getGroundItems().addListener(groundItemSync);
/* Initialize all the player options */
for (int i = 0; i < options.length; i++) {
options[i] = new PlayerOption();
}
}
public void forceMovement(ForcedMovement forcedMove) {
this.forcedMove = forcedMove;
blockActions = true;
walkingQueue.reset();
World.getWorld().getTaskScheduler().schedule(new Task(forcedMove.getDurationTicks(), false) {
@Override
public void execute() {
stop();
}
public void stop() {
teleport(forcedMove.getSecondPosition());
blockActions = false;
super.stop();
}
});
}
public ForcedMovement getForcedMove() {
return forcedMove;
}
public boolean isForceMovementUpdated() {
return forcedMove != null;
}
public boolean isChatUpdated() {
return chatMessage != null;
}
public boolean isRegionChanging() {
return regionChanging;
}
@Override
public boolean isRunning() {
return settings.isRunning();
}
/**
* Forces the player to logout. Only call from logout button.
*/
public void logout() {
ChannelFuture future = send(new LogoutMessage());
if (future != null) {
future.addListener(ChannelFutureListener.CLOSE);
}
}
protected void onDeath() {
reset();
startAction(new PlayerDeathAction(this));
}
@Override
public void reduceHp(int amount) {
skillSet.setCurrentLevel(Skill.HITPOINTS, getCurrentHitpoints() - amount);
}
public void reducePrayerPoints(int amount) {
skillSet.setCurrentLevel(Skill.PRAYER, getPrayerPoints() - amount);
}
public void refreshGroundItems() {
groundItemSync.purge();
World.getWorld().getGroundItems().fireEvents(groundItemSync);
}
public void refreshGroundObjects() {
groundObjSync.purge();
World.getWorld().getGroundObjects().fireEvents(groundObjSync);
}
public GroundObjectSynchronizer getGroundObjectSynchronizer() {
return groundObjSync;
}
public void refreshOptions() {
for (int i = 0; i < options.length; i++) {
PlayerOption option = options[i];
send(new PlayerMenuOptionMessage(i + 1, option.atTop(), option.getText()));
}
}
@Override
public void reset() {
super.reset();
updateModelLists = false;
regionChanging = false;
chatMessage = null;
constructedRegion = null;
forcedMove = null;
}
public SceneRebuiltListener getSceneRebuiltListener() {
return sceneRebuiltListener;
}
public void setSceneRebuiltListener(SceneRebuiltListener sceneRebuiltListener) {
this.sceneRebuiltListener = sceneRebuiltListener;
}
public ChannelFuture send(Message message) {
if (session != null) {
return session.send(message);
} else {
return null;
}
}
public void sendEquipmentBonuses() {
setInterfaceText(667, 32, "0 kg");
setInterfaceText(667, 36, "Stab: " + addPlus(combatBonuses.getAttackBonus(AttackType.STAB)));
setInterfaceText(667, 37, "Slash: " + addPlus(combatBonuses.getAttackBonus(AttackType.SLASH)));
setInterfaceText(667, 38, "Crush: " + addPlus(combatBonuses.getAttackBonus(AttackType.CRUSH)));
setInterfaceText(667, 39, "Magic: " + addPlus(combatBonuses.getAttackBonus(AttackType.MAGIC)));
setInterfaceText(667, 40, "Ranged: " + addPlus(combatBonuses.getAttackBonus(AttackType.RANGE)));
setInterfaceText(667, 41, "Stab: " + addPlus(combatBonuses.getDefenceBonus(AttackType.STAB)));
setInterfaceText(667, 42, "Slash: " + addPlus(combatBonuses.getDefenceBonus(AttackType.SLASH)));
setInterfaceText(667, 43, "Crush: " + addPlus(combatBonuses.getDefenceBonus(AttackType.CRUSH)));
setInterfaceText(667, 44, "Magic: " + addPlus(combatBonuses.getDefenceBonus(AttackType.MAGIC)));
setInterfaceText(667, 45, "Range: " + addPlus(combatBonuses.getDefenceBonus(AttackType.RANGE)));
setInterfaceText(667, 46, "Summoning: 0");
setInterfaceText(667, 48, "Strength: " + addPlus(combatBonuses.getStrengthBonus()));
setInterfaceText(667, 49, "Prayer: " + addPlus(combatBonuses.getPrayerBonus()));
}
public void sendMessage(String text) {
send(new ServerMessage(text));
}
public void setActionsBlocked(boolean blockActions) {
this.blockActions = blockActions;
}
public void setAppearance(Appearance appearance) {
this.appearance = appearance;
appearanceUpdated();
}
public void setChatMessage(ChatMessage message) {
this.chatMessage = message;
}
public void setDatabaseId(int databaseId) {
this.databaseId = databaseId;
}
public void setEnergy(int energy) {
this.energy = energy;
this.send(new EnergyMessage(energy));
}
@Override
public void setHidden(boolean hidden) {
super.setHidden(hidden);
appearanceUpdated();
}
public void setInterfaceText(int widgetId, int componentId, String text) {
send(new InterfaceTextMessage(widgetId, componentId, text));
}
public void setLastKnownRegion(Position lastKnownRegion) {
this.lastKnownRegion = lastKnownRegion;
World.getWorld().getGroundObjects().removeListener(groundObjSync);
GameServer.getInstance().getMapLoader().load(lastKnownRegion.getX() / 64, lastKnownRegion.getY() / 64);
World.getWorld().getGroundObjects().addListener(groundObjSync);
this.regionChanging = true;
}
public void setPassword(String password) {
this.password = password;
}
public void setPNPC(int pnpc) {
this.pnpc = pnpc;
if (pnpc == -1) {
size = 0;
} else {
size = NPCDefinitions.forId(pnpc).getSize();
}
appearanceUpdated();
}
public void setRights(int rights) {
this.rights = rights;
}
public void setSession(GameSession session) {
this.session = session;
}
public void setSpellbook(Spellbook spellbook) {
this.spellbook = spellbook;
}
public void setTradeRequest(Player other) {
wantToTrade = other;
}
public void setTradeSession(TradeSession tradeSession) {
this.tradeSession = tradeSession;
}
public void setUpdateModelLists(boolean updateModelLists) {
this.updateModelLists = updateModelLists;
}
public void setUsername(String username) {
this.username = username.replaceAll(" ", "_").toLowerCase();
displayName = StringUtils.capitalize(username);
longUsername = Base37Utils.encodeBase37(username);
}
public void startBankSession() {
bankSession = new BankSession(this);
bankSession.init();
}
@Override
public void teleport(Position position) {
interfaceSet.resetAll();
super.teleport(position);
}
public void setClipped(boolean clipped) {
this.clipped = clipped;
}
public void toggleClipping() {
clipped = !clipped;
}
public void unregister() {
World.getWorld().getGroundItems().removeListener(groundItemSync);
World.getWorld().getGroundObjects().removeListener(groundObjSync);
friends.logout();
stopAction();
}
public boolean wantsToTrade(Player other) {
return other == wantToTrade;
}
public void setConstructedRegion(RegionPalette region) {
constructedRegion = region;
}
public RegionPalette getConstructedRegion() {
return constructedRegion;
}
public void onLogin() {
grandExchangeHandler.init();
calculateEquipmentBonuses();
friends.init();
if (variables.getVar(Variable.FIRST_LOGIN) == 1) {
variables.setVar(Variable.FIRST_LOGIN, 0);
sendMessage("Welcome, thank you for joining MoparScape!");
World.getWorld().sendGlobalMessage(getDisplayName() + " has joined the server! Welcome!");
// Starter items
getInventory().add(new Item(995, 5000)); // Coins
getInventory().add(new Item(1171)); // Wooden shield
getInventory().add(new Item(1277)); // Bronze sword
getInventory().add(new Item(2309)); // Bread
getInventory().add(new Item(FishingTool.SMALL_NET.getToolId()));
getInventory().add(new Item(Hatchet.BRONZE.getItemId()));
getInventory().add(new Item(Pickaxe.BRONZE.getItemId()));
getInventory().add(new Item(Firemaking.TINDERBOX));
getInventory().add(new Item(Bow.SHORTBOW.getBowId()));
getInventory().add(new Item(Arrow.BRONZE.getArrowId(), 100));
getInventory().add(new Item(Rune.MIND.getItemId(), 500));
getInventory().add(new Item(Rune.AIR.getItemId(), 500));
getInventory().add(new Item(Rune.WATER.getItemId(), 250));
getInventory().add(new Item(Rune.EARTH.getItemId(), 250));
getInventory().add(new Item(Rune.FIRE.getItemId(), 250));
} else {
sendMessage("Welcome to MoparScape.");
World.getWorld().sendGlobalMessage(getDisplayName() + " has logged in.");
}
System.out.println("Player logged in: " + getDisplayName());
}
}