/*
* This file is part of gwap, an open platform for games with a purpose
*
* Copyright (C) 2013
* Project play4science
* Lehr- und Forschungseinheit für Programmier- und Modellierungssprachen
* Ludwig-Maximilians-Universität München
*
* This program 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.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gwap.game;
import gwap.model.GameType;
import gwap.model.Person;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import org.jboss.seam.Component;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.log.Log;
/* Class for all shared contents in a game
* PlayerMatcher ensures that all parties in a game
* share the same SharedGame object
*
* Warning: Any properties that are injected into the
* SharedGame are NOT shared
*/
public abstract class SharedGame<P extends Player<P>> implements Serializable {
@Logger private Log log;
private int currentRound=0;
protected Date roundStarted;
private long score=0;
private long lastRoundStartScore=0;
private long lastRoundEndScore;
private boolean moveMode=false;
private int movesLeft;
private int moves=15;
private String language;
//Overall number of rounds
private int roundCount=0;
private int roundLength=0;
private GameSessionBeanNew gameSessionBeanNew;
private List<P> players=new ArrayList<P>();
private GameType gameType;
/*This method is used by the PlayerMatcher to decide, whether:
* Two players can be matched
* A player is returned to their queue or created anew
*
* This is mostly important for games that have customizable parameters
*/
public abstract boolean isCompatible(SharedGame game);
public abstract void startNewRound();
public SharedGame()
{
gameSessionBeanNew=(GameSessionBeanNew)Component.getInstance("gameSessionBeanNew");
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public GameSessionBeanNew getGameSessionBeanNew() {
return gameSessionBeanNew;
}
public GameType getGameType() {
return gameType;
}
public void setGameType(GameType gameType) {
this.gameType = gameType;
}
public long getScore() {
return score;
}
public long getRoundScore() {
return score-lastRoundEndScore;
}
public void setScore(long score) {
this.score = score;
}
public void addPlayer(P player) {
players.add(player);
}
public P getPlayerByIndex(int index) {
return players.get(index);
}
public P updatePlayer(Person person)
{
ListIterator<P> lp=players.listIterator();
while (lp.hasNext())
{
P lplayer=lp.next();
if (lplayer.getPerson()==person)
return lplayer;
}
return null;
}
public boolean cleanPlayers()
{
ListIterator<P> lp=players.listIterator();
while (lp.hasNext())
{
P lplayer=lp.next();
try
{
if (lplayer.isTimedOut())
{
return true;
}
}
catch (Exception e)
{
// do nothing
}
}
return false;
}
public void move()
{
if (moveMode)
{
if (movesLeft>0)
movesLeft--;
}
}
public boolean isRunning()
{
return players.size()==2;
}
public int getCurrentRound() {
return currentRound;
}
public void setCurrentRound(int currentRound) {
this.currentRound = currentRound;
}
public int getRoundCount() {
return roundCount;
}
public int getRoundLength() {
return roundLength;
}
public void setRoundLength(int roundLength) {
this.roundLength = roundLength;
}
public void setRoundCount(int roundCount) {
this.roundCount = roundCount;
}
public boolean isTerminated()
{
return currentRound>roundCount;
}
public int getRoundRemaining() {
return (int)(roundStarted.getTime()-new Date().getTime())/1000+roundLength;
}
public boolean getMoveMode()
{
return moveMode;
}
public void setMoveMode(boolean moveMode)
{
this.moveMode=moveMode;
}
public void setMoves(int moves)
{
this.moves=moves;
}
public int getMoves()
{
return moves;
}
public int getMovesLeft()
{
return movesLeft;
}
public boolean isRoundCompleted() {
if (moveMode)
return movesLeft<=0;
else
return getRoundRemaining()<=0;
}
public synchronized boolean checkRound(int round)
{
if (isRoundCompleted())
newRound();
if (isTerminated())
{
for (Player<P> p : players) {
p.signal("endGame");
}
}
return (round!=0 && round!=currentRound) || isTerminated();
}
public Long getLastScore()
{
return lastRoundEndScore-lastRoundStartScore;
}
public synchronized void newRound()
{
if (isTerminated())
{
for (Player<P> p : players) {
p.signal("endGame");
}
return;
}
log.info("newRound()");
roundStarted=new Date();
currentRound++;
if (isFirstRound())
gameSessionBeanNew.startSession(gameType);
movesLeft=moves;
lastRoundStartScore=lastRoundEndScore;
lastRoundEndScore=score;
if (!isTerminated())
{
startNewRound();
for (Player<P> p : players) {
p.signal("newRound");
}
}
else
{
for (Player<P> p : players) {
p.signal("endGame");
}
}
}
public boolean isFirstRound()
{
return currentRound<=1;
}
}