/*
* IDK Game Server by Steve Winfield
* https://github.com/WinfieldSteve
*/
package org.stevewinfield.suja.idk.game.rooms;
import org.magicwerk.brownies.collections.GapList;
import org.stevewinfield.suja.idk.communication.ISerialize;
import org.stevewinfield.suja.idk.communication.MessageWriter;
import org.stevewinfield.suja.idk.communication.room.writers.*;
import org.stevewinfield.suja.idk.game.bots.BotInstance;
import org.stevewinfield.suja.idk.game.bots.BotPhrase;
import org.stevewinfield.suja.idk.game.furnitures.FurnitureInteractor;
import org.stevewinfield.suja.idk.game.miscellaneous.ChatMessage;
import org.stevewinfield.suja.idk.game.miscellaneous.ChatType;
import org.stevewinfield.suja.idk.game.players.PlayerInformation;
import org.stevewinfield.suja.idk.game.rooms.coordination.*;
import org.stevewinfield.suja.idk.game.rooms.coordination.Pathfinder.Node;
import org.stevewinfield.suja.idk.network.sessions.Session;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
public class RoomPlayer implements ISerialize {
public int getVirtualId() {
return virtualId;
}
public RoomInstance getRoom() {
return room;
}
public int getRoomId() {
return roomId;
}
public Vector3 getPosition() {
return position;
}
public Session getSession() {
return session;
}
public boolean needsUpdate() {
return updateNeeded;
}
public PlayerInformation getPlayerInformation() {
return playerInformation;
}
public RoomItem getFloorItem() {
return floorItem;
}
public Vector2 getGoalPosition() {
return goalPosition;
}
public int getEffectId() {
return effectId;
}
public int getHeadRotation() {
return headRotation;
}
public int getHanditemId() {
return this.handItem;
}
public int getRotation() {
return rotation;
}
public int getCurrentTileState() {
return currentTileState;
}
public int getGoalRotation() {
return goalRotation;
}
public HashMap<String, String> getStatusMap() {
return statusMap;
}
public boolean isWalking() {
return isWalking;
}
public boolean isGettingKicked() {
return gettingKicked;
}
public RoomItem getActingItem() {
return actingItem;
}
public int getEffectCache() {
return effectCache;
}
public BotInstance getBotInstance() {
return botInstance;
}
public void setEffectCache(final int cache) {
this.effectCache = cache;
}
public void setKicked(final boolean f) {
this.gettingKicked = f;
}
public int getDanceId() {
return this.danceId;
}
public boolean isBot() {
return this.bot;
}
public RoomPlayer(final int virtualId, final Session session, final int roomId, final RoomInstance room, final Vector3 position, final int rotation) {
this(virtualId, roomId, room, position, rotation);
this.session = session;
this.playerInformation = session.getPlayerInstance().getInformation();
}
public void chat(final String message) {
this.chat(message, ChatType.SAY);
}
public void chat(final String message, final int chatType) {
room.getRoomTask().offerChatMessageAdd(new ChatMessage(this, message, chatType));
}
public RoomPlayer(final int virtualId, final int roomId, final RoomInstance room, final Vector3 position, final int rotation) {
this.virtualId = virtualId;
this.roomId = roomId;
this.room = room;
this.position = position;
this.statusMap = new LinkedHashMap<>();
this.headRotation = rotation;
this.rotation = rotation;
this.goalRotation = -1;
this.passedTilesKick = 0;
this.currentTileState = -1;
}
public RoomPlayer(final int virtualId, final BotInstance botData, final int roomId, final RoomInstance room, final Vector3 position, final int rotation) {
this(virtualId, roomId, room, position, rotation);
this.botInstance = botData;
this.bot = true;
}
public void addStatus(final String key, final String value) {
this.statusMap.put(key, value);
}
public void removeStatus(final String key) {
this.statusMap.remove(key);
}
public void update() {
this.updateNeeded = true;
}
public void setUpdateNeeded(final boolean needed) {
this.updateNeeded = needed;
}
public void setWalking(final boolean walk) {
this.isWalking = walk;
}
public void setRotation(final int rot) {
this.rotation = rot;
this.headRotation = rot;
}
public void setBodyRotation(final int rot) {
this.rotation = rot;
}
public void setHeadRotation(final int rot) {
this.headRotation = rot;
}
public void setStepSetted(final boolean f) {
this.stepSetted = f;
}
public boolean stepIsSetted() {
return this.stepSetted;
}
public void whisper(final Session session, final int actorId, final String message) {
final MessageWriter writer = new RoomChatWriter(actorId, message, 0, ChatType.WHISPER);
if (this.session == null || session != this.session) {
session.writeMessage(writer);
}
if (!this.isBot()) {
this.session.writeMessage(writer);
}
}
public void setPosition(final Vector3 x) {
this.position = x;
}
public void setGoalRotation(final int rot) {
this.goalRotation = rot;
}
public void setSettedPosition(final Vector3 x) {
this.settedPosition = x;
}
public Vector3 getSettedPosition() {
return this.settedPosition;
}
public boolean isFrozen() {
return this.frozen;
}
public void setFrozen(final boolean frozen) {
this.frozen = frozen;
}
public void setActingItem(final RoomItem actingItem) {
this.actingItem = actingItem;
}
@Override
public void serialize(final MessageWriter writer) {
if (this.isBot()) {
writer.push(-1);
writer.push(this.botInstance.getBotName());
writer.push(this.botInstance.getMission());
writer.push(this.botInstance.getAvatar());
} else {
writer.push(this.playerInformation.getId());
writer.push(this.playerInformation.getPlayerName());
writer.push(this.playerInformation.getMission());
writer.push(this.playerInformation.getAvatar());
}
writer.push(this.virtualId);
writer.push(this.getPosition().getX());
writer.push(this.getPosition().getY());
writer.push(String.valueOf(this.getPosition().getAltitude()));
writer.push(this.isBot() ? 4 : 2);
writer.push(this.isBot() ? 3 : 1);
if (!this.isBot()) {
writer.push(this.playerInformation.getGender() == PlayerInformation.MALE_GENDER ? "m" : "f");
writer.push(-1);
writer.push(-1); // group id
writer.push(-1);
writer.push("");
writer.push(this.playerInformation.getScore());
}
}
public boolean moveTo(final Vector2 pos, final boolean ignoreKick, final boolean ignoreBlocking) {
return this.moveTo(pos, ignoreKick, ignoreBlocking, false);
}
public boolean moveTo(Vector2 pos, final boolean ignoreKick, final boolean ignoreBlocking, final boolean isRollerEvent) {
if ((this.walkingBlocked && !ignoreBlocking) || (this.gettingKicked && !ignoreKick)) {
return false;
}
RoomItem topItem = null;
for (final RoomItem item : room.getRoomItemsForTile(pos)) {
if ((topItem == null || item.getAbsoluteHeight() > topItem.getAbsoluteHeight()) && item.getBase().isLayable()) {
topItem = item;
}
}
if (topItem != null) {
if (topItem.getRotation() == 0 && pos.getY() != topItem.getPosition().getY()) {
pos = new Vector2(pos.getX(), pos.getY() - (pos.getY() - topItem.getPosition().getY()));
} else if (topItem.getRotation() == 2 && pos.getX() != topItem.getPosition().getX()) {
pos = new Vector2(pos.getX() - (pos.getX() - topItem.getPosition().getX()), pos.getY());
}
}
if (Pathfinder.getPathInArray(room.getGamemap().getTileStates(), room.getGamemap().getTileHeights(), this.getPosition().getVector2(), pos, this.walkingBlocked) == null) {
return false;
}
this.goalPosition = pos;
this.isWalking = true;
this.goalRotation = -1;
this.actingItem = null;
this.isRollerEvent = isRollerEvent;
return true;
}
public boolean moveTo(final Vector2 pos) {
return this.moveTo(pos, false, false, false);
}
public boolean moveTo(final Vector2 pos, final boolean isRollerEvent) {
return this.moveTo(pos, false, false, isRollerEvent);
}
public void handleVending(final int cycles, final int handItem) {
if (cycles == 0) {
this.cycles = 1;
} else {
this.frozen = true;
this.cycles = cycles;
}
this.handleVendingId = handItem;
}
public void handleVending(final int handItem) {
this.handleVending(0, handItem);
}
public boolean moveTo(final Vector2 pos, final int rot, final RoomItem actingItem) {
if (this.frozen || this.walkingBlocked) {
return false;
}
if (pos.getX() == this.getPosition().getX() && pos.getY() == this.getPosition().getY() && rot != -1) {
this.setRotation(rot);
this.setUpdateNeeded(true);
actingItem.getInteractor().onTrigger(this, actingItem, 0, this.getRoom().hasRights(this.getSession()));
return false;
}
final boolean x = this.moveTo(pos);
if (!x) {
return false;
}
this.goalRotation = rot;
this.actingItem = actingItem;
return true;
}
public void wave() {
this.room.writeMessage(new RoomPlayerWaveWriter(this.virtualId), this.getSession());
}
public void onCarryItem(final int x) {
this.room.writeMessage(new RoomPlayerCarryItemWriter(this.virtualId, x), this.getSession());
}
public void onCycle(final ConcurrentHashMap<Vector2, Integer> roomTileStates) {
if (this.stepIsSetted()) {
if ((this.room.getInformation().getModel().getDoorPosition().getX() == this.getSettedPosition().getX() &&
this.room.getInformation().getModel().getDoorPosition().getY() == this.getSettedPosition().getY()) ||
(this.gettingKicked && ++this.passedTilesKick >= 5)) {
room.removePlayerFromRoom(session, true, this.gettingKicked);
return;
}
this.setPosition(this.getSettedPosition());
this.setStepSetted(false);
final RoomItem highestItem = room.getTopItem(this.getPosition().getX(), this.getPosition().getY());
if (highestItem == null || (this.floorItem != highestItem)) {
if (this.floorItem != null) {
this.floorItem.onPlayerWalksOff(
this,
floorItem.getBase().getInteractor() != FurnitureInteractor.WF_PLATE && floorItem.getBase().getInteractor() != FurnitureInteractor.BATTLE_BANZAI_PUCK
);
this.floorItem = null;
}
if (highestItem != null) {
this.floorItem = highestItem;
highestItem.onPlayerWalksOn(
this,
highestItem.getBase().getInteractor() != FurnitureInteractor.WF_PLATE && highestItem.getBase().getInteractor() != FurnitureInteractor.BATTLE_BANZAI_PUCK
);
}
}
}
if (this.handItemCycle > 0) {
if (this.handItemTermCycles >= this.handItemCycle) {
if (this.handItem > 0) {
this.handItemTermCycles = 0;
this.handItemCycle = 0;
this.handItem = 0;
this.onCarryItem(0);
}
} else {
this.handItemTermCycles++;
}
}
if (this.cycles > 0) {
if (this.termCycles >= this.cycles) {
if (this.handleVendingId > 0) {
this.handItem = this.handleVendingId;
this.handItemTermCycles = 0;
this.danceId = 0;
this.onCarryItem(this.handItem);
this.handItemCycle = 240;
this.frozen = false;
this.handleVendingId = 0;
}
this.cycles = 0;
this.termCycles = 0;
} else {
termCycles++;
}
}
if (this.isWalking() && this.isFrozen()) {
this.setWalking(false);
this.removeStatus("mv");
this.update();
}
if (this.isWalking() && !this.isFrozen()) {
Vector2 point = this.getGoalPosition();
final Vector2 oldPoint = this.getPosition().getVector2();
boolean updateMap = false;
if (!this.isRollerEvent) {
Node l = (this.getPosition().getX() == this.getGoalPosition().getX() &&
this.getPosition().getY() == this.getGoalPosition().getY()) ?
null :
Pathfinder.getPathInArray(
room.getGamemap().getTileStates(),
room.getGamemap().getTileHeights(),
this.getPosition().getVector2(),
this.getGoalPosition(),
this.walkingBlocked
);
if (l != null) {
while (l.getParent() != null && l.getParent().getParent() != null) {
l = l.getParent();
}
}
point = l == null ? this.getPosition().getVector2() : new Vector2(l.getX(), l.getY());
} else {
this.setPosition(new Vector3(point.getX(), point.getY(), this.room.getAltitude(point)));
updateMap = true;
}
if (point.getX() == this.getPosition().getX() && point.getY() == this.getPosition().getY() || updateMap) {
this.setWalking(false);
this.removeStatus("mv");
if (updateMap) {
this.setSettedPosition(this.getPosition());
this.setStepSetted(true);
}
if (this.getPosition().getX() == this.getGoalPosition().getX() && this.getPosition().getY() == this.getGoalPosition().getY()) {
if (this.getGoalRotation() != -1) {
this.setRotation(this.getGoalRotation());
this.setGoalRotation(-1);
}
if (this.getActingItem() != null) {
this.getActingItem().getInteractor().onTrigger(this, this.getActingItem(), 0, this.room.hasRights(this.getSession()));
this.setActingItem(null);
}
} else if (this.gettingKicked) {
room.removePlayerFromRoom(session, true, true);
return;
} else if (this.getGoalRotation() != -1) {
this.setGoalRotation(-1);
}
int state;
if ((state = room.getGamemap().getTileState(this.getPosition().getX(), this.getPosition().getY())) == TileState.SITABLE ||
state == (TileState.SITABLE | TileState.PLAYER) || state == (TileState.SITABLE | TileState.BLOCKED)) {
RoomItem highestItem = null;
for (final RoomItem item : room.getRoomItemsForTile(this.getPosition().getVector2())) {
if ((highestItem == null || item.getAbsoluteHeight() > highestItem.getAbsoluteHeight()) && item.getBase().isSitable()) {
highestItem = item;
}
}
if (highestItem != null) {
this.setRotation(highestItem.getRotation());
this.addStatus("sit", String.valueOf(highestItem.getBase().getHeight()));
}
} else if ((state = room.getGamemap().getTileState(this.getPosition().getX(), this.getPosition().getY())) == TileState.LAYABLE ||
state == (TileState.LAYABLE | TileState.PLAYER) || state == (TileState.LAYABLE | TileState.BLOCKED)) {
final RoomItem highestItem = room.getTopItem(getPosition().getX(), getPosition().getY());
if (highestItem != null) {
if (highestItem.getRotation() == 2) {
if (this.getPosition().getX() != highestItem.getPosition().getX()) {
this.setPosition(new Vector3(highestItem.getPosition().getX(), this.getPosition().getY(), this.getPosition().getAltitude()));
}
} else if (highestItem.getRotation() == 0) {
if (this.getPosition().getY() != highestItem.getPosition().getY()) {
this.setPosition(new Vector3(this.getPosition().getX(), highestItem.getPosition().getY(), this.getPosition().getAltitude()));
}
}
this.setRotation(highestItem.getRotation());
this.addStatus("lay", String.valueOf(highestItem.getBase().getHeight()) + " null");
}
}
} else {
updateMap = true;
}
if (updateMap) {
final int nextX = point.getX();
final int nextY = point.getY();
if (!this.isRollerEvent) {
this.removeStatus("sit");
this.removeStatus("lay");
this.removeStatus("mv");
}
final RoomItem highestItem = room.getTopItem(nextX, nextY);
if (highestItem == null || (this.floorItem != highestItem)) {
if (this.floorItem != null) {
if (this.floorItem.getBase().getEffectId() > 0) {
this.applyEffect(this.effectCache > 0 ? this.effectCache : 0);
if (this.effectCache > 0) {
this.effectCache = 0;
}
}
if (floorItem.getBase().getInteractor() == FurnitureInteractor.WF_PLATE || floorItem.getBase().getInteractor() == FurnitureInteractor.BATTLE_BANZAI_PUCK) {
floorItem.getInteractor().onPlayerWalksOff(this, floorItem);
}
}
if (highestItem != null) {
if (highestItem.getBase().getEffectId() > 0) {
if (this.effectId == RoomPlayerEffect.BANZAI_BLUE || this.effectId == RoomPlayerEffect.BANZAI_GREEN || this.effectId == RoomPlayerEffect.BANZAI_ORANGE || this.effectId == RoomPlayerEffect.BANZAI_PINK) {
this.effectCache = this.effectId;
}
this.applyEffect(highestItem.getBase().getEffectId());
}
if (highestItem.getBase().getInteractor() == FurnitureInteractor.WF_PLATE) {
highestItem.getInteractor().onPlayerWalksOn(this, highestItem);
} else if (highestItem.getBase().getInteractor() == FurnitureInteractor.BATTLE_BANZAI_PUCK) {
if (this.trigger) {
highestItem.getInteractor().onTrigger(this, highestItem, 1, this.getSession() != null && room.hasRights(this.getSession()));
// this.trigger = false;
} else {
highestItem.getInteractor().onPlayerWalksOn(this, highestItem);
}
}
}
}
if (!this.isRollerEvent) {
final double nextAltitude = this.room.getAltitude(new Vector2(nextX, nextY));
this.addStatus("mv", nextX + "," + nextY + "," + String.valueOf(nextAltitude));
this.setRotation(Rotation.calculate(this.getPosition().getX(), this.getPosition().getY(), nextX, nextY));
this.setStepSetted(true);
this.setSettedPosition(new Vector3(nextX, nextY, nextAltitude));
}
if (this.currentTileState != -1) {
roomTileStates.put(oldPoint, this.currentTileState);
//this.getRoom().getGamemap().updateTile(oldPoint, this.currentTileState);
}
this.currentTileState = this.getRoom().getGamemap().getTileState(point.getX(), point.getY());
final boolean oxi = this.currentTileState == TileState.SITABLE || this.currentTileState == TileState.LAYABLE;
roomTileStates.put(point, this.getRoom().getInformation().blockingDisabled() ? (TileState.PLAYER | (oxi ? this.currentTileState : 0)) : (TileState.BLOCKED | (oxi ? this.currentTileState : 0)));
}
this.update();
}
if (this.isBot()) {
if (this.botInstance.isMovingEnabled() && this.botMoveCycles-- == 0) {
final Vector2 position = this.getPosition().getVector2();
final GapList<Vector2> randomTiles = new GapList<>();
for (final Vector2 vector : Pathfinder.DIRECTIONS) {
int state;
if (((state = this.getRoom().getGamemap().getTileState(position.getX() + vector.getX(), position.getY() + vector.getY())) == TileState.OPEN || state == TileState.SITABLE) && (room.getInformation().getModel().getDoorPosition().getX() != (position.getX() + vector.getX()) || room.getInformation().getModel().getDoorPosition().getY() != position.getY() + vector.getY())) {
randomTiles.add(new Vector2(position.getX() + vector.getX(), position.getY() + vector.getY()));
}
}
if (randomTiles.size() > 0) {
this.moveTo(randomTiles.get((new Random()).nextInt(randomTiles.size())));
}
this.botMoveCycles = new Random().nextInt(15) + 1;
}
if (this.botInstance.getPhrases().size() > 0 && this.botPhraseCylces-- == 0) {
final BotPhrase phrase = this.botInstance.getPhrases().get(new Random().nextInt(this.botInstance.getPhrases().size()));
this.chat(phrase.getPhrase(), phrase.isShouted() ? ChatType.SHOUT : ChatType.SAY);
this.botPhraseCylces = new Random().nextInt(35) + 45;
}
if (this.botCycles > 0 && --this.botCycles == 0) {
this.getBotInstance().getInteractor().onCycle(this);
}
}
}
public void applyEffect(final int effectId) {
if (this.effectId == effectId) {
return;
}
if (this.effectId == RoomPlayerEffect.BANZAI_BLUE || this.effectId == RoomPlayerEffect.BANZAI_GREEN || this.effectId == RoomPlayerEffect.BANZAI_ORANGE || this.effectId == RoomPlayerEffect.BANZAI_PINK) {
this.effectCache = this.effectId;
}
this.effectId = effectId;
this.getRoom().writeMessage(new RoomPlayerEffectWriter(this.getVirtualId(), effectId), null);
}
public void dance(int danceId) {
if (danceId == this.danceId) {
return;
}
if (danceId < 1 || danceId > 4) {
danceId = 0;
}
if (danceId > 1 && !session.getPlayerInstance().hasClub()) {
danceId = 1;
}
this.danceId = danceId;
this.handItem = 0;
this.onCarryItem(0);
this.room.writeMessage(new RoomPlayerDanceWriter(this.virtualId, danceId), session);
}
public void setFloorItem(final RoomItem item) {
this.floorItem = item;
}
public void setCurrentTileState(final int tileState) {
this.currentTileState = tileState;
}
public void requestBotCycles(final int cycles) {
if (!this.isBot()) {
return;
}
this.botCycles = cycles;
}
public void setWalkingBlocked(final boolean blocked) {
if (blocked) {
this.isWalking = false;
}
this.walkingBlocked = blocked;
}
// fields
private final int virtualId;
private final RoomInstance room;
private Session session;
private BotInstance botInstance;
private boolean bot;
private final int roomId;
private boolean updateNeeded;
private PlayerInformation playerInformation;
private Vector3 position;
private final HashMap<String, String> statusMap;
private int headRotation;
private int rotation;
private Vector2 goalPosition;
private int effectId;
private boolean isWalking;
private boolean stepSetted;
private boolean gettingKicked;
private boolean trigger;
private Vector3 settedPosition;
private int goalRotation;
private RoomItem actingItem;
private RoomItem floorItem;
private int cycles;
private int botCycles;
private int botMoveCycles;
private int botPhraseCylces;
private int termCycles;
private boolean frozen;
private boolean walkingBlocked;
private int handleVendingId;
private int handItem;
private int handItemCycle;
private int handItemTermCycles;
private int danceId;
private int passedTilesKick;
private int effectCache;
private int currentTileState;
private boolean isRollerEvent;
}