package jk_5.nailed.server.map.game;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import jk_5.nailed.api.chat.ChatColor;
import jk_5.nailed.api.chat.ComponentBuilder;
import jk_5.nailed.api.map.*;
import jk_5.nailed.api.map.stat.StatEvent;
import jk_5.nailed.api.player.Player;
import jk_5.nailed.api.util.TitleMessage;
import jk_5.nailed.server.NailedPlatform;
import jk_5.nailed.server.map.game.script.ScriptingEngine;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class NailedGameManager implements GameManager {
private final Map map;
private final ScriptingEngine scriptingEngine = new ScriptingEngine(this);
private boolean isGameRunning = false;
private boolean winInterrupt = false;
private boolean unreadyInterrupt = false;
private GameWinnable winner;
public NailedGameManager(Map map) {
this.map = map;
}
@Override
@Nonnull
public GameStartResult startGame() {
if(isGameRunning){
return new GameStartResult(false, "A game is already running");
}
try{
List<Player> missingPlayers = new ArrayList<Player>();
for (Team team : map.getTeams()) {
for (Player member : team.members()) {
if(member.getMap() != map){
missingPlayers.add(member);
}
}
}
if(missingPlayers.size() > 0){
List<String> missingNames = new ArrayList<String>();
for (Player player : missingPlayers) {
missingNames.add(player.getName());
}
String names = Joiner.on(", ").join(missingNames);
return new GameStartResult(false, "Game could not be started because the following players are not in the map: " + names);
}
boolean scriptStarted = scriptingEngine.start();
if(hasCustomGameType()){
getGameType().onGameStarted(map);
}
isGameRunning = scriptStarted || hasCustomGameType();
if(!isGameRunning){
return new GameStartResult(false, "game.js could not be found or read");
}
map.getStatManager().fireEvent(new StatEvent("gameRunning", true));
return new GameStartResult(true, null);
}catch(Exception e){
return new GameStartResult(false, "Exception while starting game", e);
}
}
@Override
public boolean endGame() {
if(!isGameRunning){
return false;
}
isGameRunning = false;
if(hasCustomGameType()){
getGameType().onGameEnded(map);
}
scriptingEngine.kill();
map.getStatManager().fireEvent(new StatEvent("gameRunning", false));
cleanup();
return true;
}
public void onEnded(boolean success){
if(!isGameRunning){
return;
}
isGameRunning = false;
if(this.hasCustomGameType()){
getGameType().onGameEnded(map);
}
map.getStatManager().fireEvent(new StatEvent("gameRunning", false));
cleanup();
}
@Override
public void setWinner(@Nonnull GameWinnable winner) {
if(this.winner != null){
return;
}
this.winner = winner;
TitleMessage.Builder builder = TitleMessage.builder().setFadeInTime(0).setDisplayTime(200).setFadeOutTime(40);
builder.setTitle(new ComponentBuilder("You Win!").color(ChatColor.GREEN).create());
if(winner instanceof Player){
Player p = (Player) winner;
p.displayTitle(builder.build());
TitleMessage.Builder b2 = TitleMessage.builder().setFadeInTime(0).setDisplayTime(200).setFadeOutTime(40);
TitleMessage t2 = b2.setTitle(new ComponentBuilder("You lost!").color(ChatColor.RED).create()).build();
for (Player player : map.players()) {
if(player != p){
player.displayTitle(t2);
}
}
}else if(winner instanceof Team){
Team t = (Team) winner;
TitleMessage title = builder.build();
for (Player player : t.members()) {
player.displayTitle(title);
}
TitleMessage.Builder b2 = TitleMessage.builder().setFadeInTime(0).setDisplayTime(200).setFadeOutTime(40);
TitleMessage t2 = b2.setTitle(new ComponentBuilder("You lost!").color(ChatColor.RED).create()).build();
for (Team team : map.getTeams()) {
if(team != t){
for (Player player : team.members()) {
player.displayTitle(t2);
}
}
}
map.getStatManager().fireEvent(new StatEvent("teamWon", true, ImmutableMap.of("team", t.id())));
}
map.broadcastChatMessage(new ComponentBuilder(winner.getName() + " won the game").color(ChatColor.GOLD).create());
onEnded(true);
map.getStatManager().fireEvent(new StatEvent("gameHasWinner", true));
if(winInterrupt){
scriptingEngine.kill();
}
}
@Override
public boolean isGameRunning() {
return false;
}
@Override
public boolean hasCustomGameType() {
return getGameType() != null;
}
@Nullable
@Override
public GameType getGameType() {
if(map.mappack() != null){
return NailedPlatform.instance().getGameTypeRegistry().getByName(map.mappack().getMetadata().gameType());
}else{
return null;
}
}
@Override
public void setWinInterrupt(boolean winInterrupt) {
this.winInterrupt = winInterrupt;
}
@Override
public boolean isWinInterrupt() {
return this.winInterrupt;
}
@Override
public void setUnreadyInterrupt(boolean unreadyInterrupt) {
this.unreadyInterrupt = unreadyInterrupt;
}
@Override
public boolean isUnreadyInterrupt() {
return this.unreadyInterrupt;
}
private void cleanup(){
for (Player player : map.players()) {
player.clearSubtitle();
}
}
public Map getMap() {
return map;
}
}