/*
* AQP Project
* http://http://code.google.com/p/aqp-project/
* Alexandre Gomez - Clément Troesch - Fabrice Latterner
*/
package com.aqpproject.worldmodel.game.state;
import com.aqpproject.game.Singleton;
import com.aqpproject.tools.Interpolation;
import com.aqpproject.tools.Vector2D;
import com.aqpproject.visualisation.Visualisation;
import com.aqpproject.worldmodel.Control;
import com.aqpproject.worldmodel.GameState;
import com.aqpproject.worldmodel.data.*;
import com.aqpproject.worldmodel.data.Map;
import com.aqpproject.worldmodel.game.WorldModelGame;
import com.aqpproject.worldmodel.game.entity.*;
import java.io.File;
import java.io.IOException;
import java.util.Map.Entry;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
*
* @author Clement
*/
public class RaceGameState implements GameState {
/**
* Constructor
*/
public RaceGameState() {
m_initialized = false;
m_car = "car1";
m_map = "Map1";
m_mode = "Mono";
m_entityPlayer = "player";
m_pos = 1;
}
public RaceGameState(String mode, String name, String map, String car, int position) {
m_initialized = false;
m_mode = mode;
m_car = car;
m_map = map;
m_pos = position;
m_entityPlayer = name;
m_carsList = new ArrayList<>();
//Singleton.getOptionsController().setMode("MONO");
}
public RaceGameState(String mode, String name, String map, ArrayList<Integer> posList, ArrayList<String> pseudoList, ArrayList<String> idList, ArrayList<String> carList) {
m_initialized = false;
m_mode = mode;
m_entityPlayer = name;
m_car = carList.get(idList.indexOf(name));
m_pos = posList.get(idList.indexOf(name));
m_map = map;
m_carsList = carList;
m_posList = posList;
m_pseudoList = pseudoList;
m_idList = idList;
Singleton.getOptionsController().setRole("MONO");
}
/**
* @see WorldModel#initialize()
*/
@Override
public void initialize() {
if (!m_initialized) { //If not initialize
Singleton.getOptionsController().setFinished(false);
m_worldEntities = new HashMap<>();
m_maps = new HashMap<>();
m_cars = new HashMap<>();
m_dynamicObjects = new HashMap<>();
m_entitiesList = new ArrayList<>();
m_carsOrigin = new ArrayList<>();
m_finishTimes = new ArrayList<>();
m_arrivalOrder = new ArrayList<>();
m_highScoreClient = new ArrayList<>();
for (int i = 0; i < 8; i++) {
m_highScoreClient.add(false);
}
m_finishNames = new ArrayList<>();
m_weCars = new ArrayList<>();
m_raceEnd = null;
m_miniMap = null;
m_isUpdating = false;
m_startTime = -1;
m_trollEmitter = null;
m_trollingTime = 0;
m_tabTime = 0;
m_lastCameraPosition = m_cameraPosition = new Vector2D();
m_scoreManager = new HighScoreManager("config/highscores.xml");
m_lastActionTimming = Singleton.getWorldModel().getTime();
Singleton.getPhysics().setActive(false);
try {
loadMaps("config/maps.xml");
loadObjects("config/cars.xml", true);
loadObjects("config/dynamic_objects.xml", false);
} catch (ParserConfigurationException | IOException | SAXException ex) {
Logger.getLogger(WorldModelGame.class.getName()).log(Level.SEVERE, null, ex);
}
try {
m_itemsController = new ItemController("config/items.xml", 100, 5000);
} catch (ParserConfigurationException | SAXException | IOException ex) {
Logger.getLogger(RaceGameState.class.getName()).log(Level.SEVERE, null, ex);
}
createEntities();
//Active physic in server role
if ("SERVER".equals(Singleton.getOptionsController().getRole())) {
Singleton.getPhysics().setActive(true);
}
Singleton.getVisualisation().setZoom(1.5f);
//Initialisation
m_initialized = true;
}
}
/**
* @see WorldModel#destroy()
*/
@Override
public void destroy() {
Singleton.getIA().clear();
//Inventory
for (WECar c : m_weCars) {
if (c.getName().equals(m_entityPlayer)) {
c.getInventory().removeMiniatures();
}
}
//Entities
for (WorldEntity e : m_worldEntities.values()) {
e.destroy();
}
m_miniMap.destroy();
m_countDown.destroy();
m_informations.destroy();
m_counter.destroy();
m_wrongDirection.destroy();
m_raceEnd.destroy();
//Destroy Map
//TODO: Create Map Entity
Singleton.getVisualisation().deleteMap();
Singleton.getPhysics().deleteMapBodies();
Singleton.getVisualisation().setZoom(1.f);
}
/**
* Load a map
*
* @param path path to the map
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
*/
private void loadMaps(String path) throws ParserConfigurationException, IOException, SAXException {
File file = new File(path);
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(file);
doc.getDocumentElement().normalize();
Element root = doc.getDocumentElement();
NodeList children = root.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node n = children.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE) {
Element e = (Element) n;
String name = e.getAttribute("name");
String mapPath = e.getAttribute("path");
String miniMap = e.getAttribute("mini");
int nbLaps = Integer.parseInt(e.getAttribute("laps"));
m_maps.put(name, new Map(name, mapPath, miniMap, nbLaps));
}
}
}
/**
* Create the entities
*/
private void createEntities() {
//Map
Singleton.getVisualisation().createMap(m_maps.get(m_map).getPath());
Singleton.getPhysics().createMapBodies();
m_miniMap = new WEMiniMap(m_maps.get(m_map).getMiniMap());
//GUI
m_informations = new WEInformations(m_maps.get(m_map).getLaps());
m_counter = new WECounter();
//Boxes
ArrayList<Vector2D> boxes_positions = Singleton.getVisualisation().getTilePositions(Visualisation.MAP_LAYER.INFORMATIONS, 14);
for (Vector2D v : boxes_positions) {
String name = "box_" + v.x + "_" + v.y;
m_worldEntities.put(name, new WEBox(name, "box", v, 0, 1, m_itemsController));
//System.out.println(name);
}
if ("MONO".equals(Singleton.getOptionsController().getMode())) {
//Player
m_entityPlayer = "player";
m_worldEntities.put(m_entityPlayer, new WECar(m_entityPlayer, getCarPosition(m_pos, m_cars.get(m_car)), 0, m_cars.get(m_car), 1, this, "Player 1"));
((WECar) (m_worldEntities.get(m_entityPlayer))).setMyCar(true);
m_miniMap.addEntity(m_worldEntities.get(m_entityPlayer), true);
m_weCars.add((WECar) m_worldEntities.get(m_entityPlayer));
m_carsOrigin.add((WECar) (m_worldEntities.get("player")));
for (int i = 1; i < 8; i++) {
String name = Singleton.getRandomController().getName();
String car = Singleton.getRandomController().getCar();
Vector2D pos = getCarPosition(i + 1, m_cars.get(car));
System.out.println(pos.toString());
m_worldEntities.put("bot" + i, new WECar("bot" + i, pos, 0, m_cars.get(car), 1, this, name));
m_miniMap.addEntity(m_worldEntities.get("bot" + i), false);
m_weCars.add((WECar) m_worldEntities.get("bot" + i));
m_carsOrigin.add((WECar) (m_worldEntities.get("bot" + i)));
Singleton.getIA().addController("bot" + i);
}
}
if ("MULTI".equals(Singleton.getOptionsController().getMode())) {
for (int i = 0; i < m_idList.size(); i++) {
String id = m_idList.get(i);
String car = m_carsList.get(i);
int pos = m_posList.get(i);
String pseudo = m_pseudoList.get(i);
m_worldEntities.put(id, new WECar(id, getCarPosition(pos, m_cars.get(car)), 0, m_cars.get(car), 1, this, pseudo));
m_weCars.add((WECar) m_worldEntities.get(id));
m_carsOrigin.add((WECar) m_worldEntities.get(id));
if (id.equals(m_entityPlayer)) {
m_miniMap.addEntity(m_worldEntities.get(id), true);
((WECar) (m_worldEntities.get(m_entityPlayer))).setMyCar(true);
} else {
m_miniMap.addEntity(m_worldEntities.get(id), false);
}
if (Singleton.getOptionsController().getRole().equals("SERVER") && i >= Singleton.getNetwork().getNbPlayers()) {
Singleton.getIA().addController(m_idList.get(i));
}
}
}
m_raceEnd = new WERaceEnd(m_weCars.size());
//IA
// Singleton.getIA().addController("bot1");
// Singleton.getIA().addController("bot2");
// Singleton.getIA().addController(m_entityPlayer);
//Dynamic Objects
for (String s : m_dynamicObjects.keySet()) {
ArrayList<Vector2D> positions = Singleton.getVisualisation().getTilePositions(Visualisation.MAP_LAYER.DYNAMIC_OBJECTS, Integer.parseInt(s));
for (Vector2D v : positions) {
String name = "dynamic" + m_worldEntities.size();
m_worldEntities.put(name, new WorldPhysicEntity(name, m_dynamicObjects.get(s), v.translate(32, 32), 1));
}
}
//WrongDirection
m_wrongDirection = new WEWrongDirection("WrongDirection", "WrongDirection", new Vector2D(), 0, 1);
//Countdown
m_countDown = new WECountdown();
m_countDown.start();
}
private void loadObjects(String path, boolean car) throws ParserConfigurationException, IOException, SAXException {
File file = new File(path);
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(file);
doc.getDocumentElement().normalize();
Element root = doc.getDocumentElement();
NodeList children = root.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node n = children.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE) {
Element e = (Element) n;
String name = e.getAttribute("name");
String spriteName = e.getAttribute("spriteName");
float density = Float.parseFloat(e.getAttribute("density"));
float linearDamping = Float.parseFloat(e.getAttribute("linearDamping"));
float angularDamping = Float.parseFloat(e.getAttribute("angularDamping"));
//Box
if (e.getChildNodes().item(1).getNodeType() == Node.ELEMENT_NODE) {
Element box = (Element) e.getChildNodes().item(1);
float width = Float.parseFloat(box.getAttribute("width"));
float height = Float.parseFloat(box.getAttribute("height"));
if (car) {
float linearSpeed = Float.parseFloat(e.getAttribute("linearSpeed"));
float angularSpeed = Float.parseFloat(e.getAttribute("angularSpeed"));
m_cars.put(name, new Car(name, spriteName, density, linearDamping, angularDamping, new Vector2D(width, height), linearSpeed, angularSpeed));
} else {
int tileCode = Integer.parseInt(e.getAttribute("tileCode"));
m_dynamicObjects.put("" + tileCode, new DynamicObject(name, spriteName, density, linearDamping, angularDamping, new Vector2D(width, height), tileCode));
}
}
}
}
}
/**
* @see WorldModel#update()
*/
@Override
public void update() {
m_isUpdating = true;
if (m_initialized) {
long time = Singleton.getWorldModel().getTime();
//Troll
if (m_isTrolling && time - m_trollingTime > 5000) {
m_isTrolling = false;
}
//Update Entities + search for inactive entities
ArrayList<String> toDelete = new ArrayList();
m_entitiesList.removeAll(m_entitiesList);
for (Entry e : m_worldEntities.entrySet()) {
if (((WorldEntity) e.getValue()).isActive()) {
((WorldEntity) e.getValue()).update(time);
m_entitiesList.add(e.getKey().toString());
} else {
toDelete.add(e.getKey().toString());
}
}
//Delete inactive entities
for (String s : toDelete) {
if (m_worldEntities.containsKey(s)) {
m_worldEntities.get(s).destroy();
m_worldEntities.remove(s);
}
}
//Update camera position
if (m_entityPlayer != null) {
m_cameraPosition = Singleton.getPhysics().getBodyCenter(m_entityPlayer);
}
//Update other informations
m_miniMap.update(time);
m_countDown.update(time);
if (m_startTime == -1 && m_countDown.isRaceStarted()) {
m_startTime = time;
}
computePosition();
WECar car = (WECar) m_worldEntities.get(m_entityPlayer);
if (!Singleton.getOptionsController().getRole().equals("SERVER")) {
int i = 0;
for (String s : m_finishNames) {
if (!m_highScoreClient.get(i)) {
m_scoreManager.addScore(m_map, s, m_finishTimes.get(i));
m_highScoreClient.set(i, true);
}
i++;
}
}
if (!Singleton.getOptionsController().getFinished() && Singleton.getOptionsController().getRole().equals("SERVER")) {
//Ajout des véhicules dans le tableau d'arrivée
for (WECar c : m_weCars) {
Vector2D pos = c.getPosition();
System.out.println(pos.toString());
if (c.getLap() == (m_maps.get(m_map).getLaps() + 1) && !m_arrivalOrder.contains(c.getName())) {
Singleton.getIA().addController(c.getName());
m_arrivalOrder.add(c.getName());
m_finishNames.add(c.getPlayerName());
m_finishTimes.add(time - m_startTime);
m_scoreManager.addScore(m_map, c.getPlayerName(), time - m_startTime);
}
}
}
if (!Singleton.getOptionsController().getFinished() && car.getLap() == (m_maps.get(m_map).getLaps() + 1)) {
Singleton.getOptionsController().setFinished(true);
/*
* if(Singleton.getOptionsController().getRole().equals("SERVER"))
* { Singleton.getIA().addController(m_entityPlayer); }
*
*/
m_raceEnd.setActivated(true);
//m_raceEnd = new WERaceEnd(m_weCars.size());
if (Singleton.getOptionsController().getRole().equals("SERVER")) {
for (int i = 0; i < m_arrivalOrder.size(); i++) {
m_raceEnd.addPosition(m_finishNames.get(i), m_finishTimes.get(i));
}
}
}
if (Singleton.getOptionsController().getFinished()) {
m_raceEnd.setActivated(true);
if (Singleton.getOptionsController().getRole().equals("SERVER")) {
for (WECar c : m_weCars) {
if (c.getLap() == (m_maps.get(m_map).getLaps() + 1) && !m_arrivalOrder.contains(c.getName())) {
m_arrivalOrder.add(c.getName());
m_finishTimes.add(time - m_startTime);
m_finishNames.add(c.getPlayerName());
m_raceEnd.addPosition(c.getPlayerName(), time - m_startTime);
m_scoreManager.addScore(m_map, c.getPlayerName(), time - m_startTime);
}
}
} else {
m_raceEnd.setPlayerList(m_finishNames);
m_raceEnd.setTimeList(m_finishTimes);
}
m_raceEnd.update();
}
m_wrongDirection.setWrongDirection(car.isInTheWrongDirection());
m_informations.updateLap(car.getLap());
m_counter.updateSpeed(car.getLinearVelocity().length() * 100);
if (m_startTime > -1) {
m_informations.updateTime(time - m_startTime);
}
}
m_isUpdating = false;
}
/**
* @see WorldModel#controlEntity(java.lang.String,
* com.aqpproject.worldmodel.Control)
*/
@Override
public void control(Control control) {
control(control, m_entityPlayer);
}
@Override
public void control(Control control, String entity) {
if (m_initialized && m_countDown.isRaceStarted()) {;
if (m_worldEntities.containsKey(entity)) {
if ((control == Control.Z || control == Control.GP_R2) && !Singleton.getPhysics().isPaused()) {
m_worldEntities.get(entity).moveForward();
} else if ((control == Control.S || control == Control.GP_L2) && !Singleton.getPhysics().isPaused()) {
m_worldEntities.get(entity).moveBackward();
} else if ((control == Control.Q || control == Control.GP_LEFT) && !Singleton.getPhysics().isPaused()) {
m_worldEntities.get(entity).rotateLeft();
} else if ((control == Control.D || control == Control.GP_RIGHT) && !Singleton.getPhysics().isPaused()) {
m_worldEntities.get(entity).rotateRight();
} else if ((control == Control.SPACE || control == Control.GP_X) && !Singleton.getPhysics().isPaused()) {
m_worldEntities.get(entity).useItem();
} else if ((control == Control.SHIFT_LEFT || control == Control.GP_A) && !Singleton.getPhysics().isPaused()) {
m_worldEntities.get(entity).shift();
} else if (control == Control.ESCAPE) {
Singleton.getWorldModel().setNextState(new MainMenuGameState());
} else if (control == Control.TAB && Singleton.getOptionsController().getFinished() && Singleton.getWorldModel().getTime() - m_tabTime > 300) {
for (WECar c : m_carsOrigin) {
if (c.getName().equals(m_entityPlayer)) {
int index = m_carsOrigin.indexOf(c);
if (index + 1 >= m_carsOrigin.size()) {
index = 0;
} else {
index++;
}
c.getInventory().removeMiniatures();
m_entityPlayer = m_carsOrigin.get(index).getName();
m_carsOrigin.get(index).getInventory().updateMiniatures();
m_tabTime = Singleton.getWorldModel().getTime();
break;
}
}
} else if (control == Control.ENTER && Singleton.getOptionsController().getFinished()) {
Singleton.getWorldModel().setNextState(new MainMenuGameState());
}
if ((control == Control.P || control == Control.GP_START) && Singleton.getWorldModel().getTime() > m_lastActionTimming + 500) {
if (!Singleton.getPhysics().isPaused()) {
Singleton.getPhysics().setPause(true);
m_pausePosition = Singleton.getPhysics().getBodyCenter(m_entityPlayer);
m_pausePosition.x = m_pausePosition.x - 256;
m_pausePosition.y = m_pausePosition.y - 128;
m_worldEntities.put("pause", new WEMenu("pause", "pause", m_pausePosition, 0, 1));
Singleton.getVisualisation().setActorAlpha("pause", 1.0f);
} else {
Singleton.getVisualisation().setActorAlpha("pause", 0.0f);
Singleton.getVisualisation().getActor("pause").remove();
//TO-DO : détruire l'objet de manière safe
Singleton.getPhysics().setPause(false);
}
m_lastActionTimming = Singleton.getWorldModel().getTime();
}
}
}
}
/**
* @see WorldModel#updateActorTransform()
*/
@Override
public void updateActorTransform() {
if (m_initialized) {
if (m_isUpdating) {
return;
}
//Camera
Vector2D camPos = Interpolation.getPositionInterpolation(m_lastCameraPosition, m_cameraPosition, Singleton.getWorldModel().getInterpolation());
Singleton.getVisualisation().setCameraPosition(camPos.x, camPos.y);
//Entities
try {
for (String s : m_entitiesList) {
if (!m_isUpdating && s != null && m_worldEntities.get(s) != null) {
m_worldEntities.get(s).updateActorTransform();
}
}
} catch (ConcurrentModificationException | NoSuchElementException e) {
System.out.println("Info: Update Actor Transform Resynchronisation");
}
/*
* for (WorldEntity e : m_worldEntities.values()) { if
* (e.isActive()) { e.updateActorTransform(); } }
*/
m_miniMap.updateActorTransform();
m_wrongDirection.updateActorTransform();
m_informations.updateActorTransform();
m_counter.updateActorTransform();
}
}
/**
* @see WorldModel#saveEntitiesState()
*/
@Override
public void saveEntitiesState() {
if (m_initialized) {
m_lastCameraPosition = m_cameraPosition;
for (WorldEntity e : m_worldEntities.values()) {
e.saveTransform();
}
}
}
@Override
public boolean isInitialized() {
return m_initialized;
}
private Vector2D getCarPosition(int pos, Car car) {
float shift = 25 - (car.m_size.x / 2.f);
ArrayList<Vector2D> v = Singleton.getVisualisation().getTilePositions(Visualisation.MAP_LAYER.INFORMATIONS, pos);
if (v.isEmpty()) {
return new Vector2D();
}
return v.get(0).translate(shift, 16);
}
@Override
public void startContact(String firstEntity, String secondEntity, Vector2D normal, Vector2D point) {
WorldPhysicEntity first = (WorldPhysicEntity) (("StaticBody".equals(firstEntity)) ? null : m_worldEntities.get(firstEntity));
WorldPhysicEntity second = (WorldPhysicEntity) (("StaticBody".equals(secondEntity)) ? null : m_worldEntities.get(secondEntity));
if (first != null) {
if (second == null) {
first.startStaticContact(normal, point);
} else {
first.startContact(second, normal, point);
second.startContact(first, normal, point);
}
} else if (second != null) {
second.startStaticContact(normal, point);
}
}
@Override
public void stopContact(String firstEntity, String secondEntity, Vector2D normal, Vector2D point) {
WorldPhysicEntity first = (WorldPhysicEntity) (("StaticBody".equals(firstEntity)) ? null : m_worldEntities.get(firstEntity));
WorldPhysicEntity second = (WorldPhysicEntity) (("StaticBody".equals(secondEntity)) ? null : m_worldEntities.get(secondEntity));
if (first != null) {
if (second == null) {
first.stopStaticContact(normal, point);
} else {
first.stopContact(second, normal, point);
second.stopContact(first, normal, point);
}
} else if (second != null) {
second.stopStaticContact(normal, point);
}
}
@Override
public HashMap<String, WorldEntity> getWorldEntities() {
return m_worldEntities;
}
public void activateTroll(WECar emitter) {
if (m_worldEntities.get(m_entityPlayer) != emitter) { //TODO: replace with a !=
if (!m_worldEntities.containsKey("troll")) {
m_worldEntities.put("troll", new WETroll("troll"));
m_trollEmitter = emitter;
} else if (m_trollEmitter != emitter) {
WETroll troll = (WETroll) m_worldEntities.get("troll");
troll.resetTime();
m_trollEmitter = emitter;
}
} else {
m_trollEmitter = emitter;
}
m_isTrolling = true;
m_trollingTime = Singleton.getWorldModel().getTime();
}
public void computePosition() {
Collections.sort(m_weCars);
for (int i = 0; i < m_weCars.size(); i++) {
if (m_weCars.get(i).getName().equals(m_entityPlayer)) {
m_informations.updatePosition(i + 1, m_weCars.size());
return;
}
}
}
public String getPlayerName() {
return m_entityPlayer;
}
public ArrayList<WECar> getCars() {
return m_carsOrigin;
}
public WECar getTrollEmitter() {
return m_trollEmitter;
}
public boolean getIsTrolling() {
return m_isTrolling;
}
public void setIsTrolling(boolean b) {
m_isTrolling = b;
}
public ArrayList<Long> getFinishTimes() {
return m_finishTimes;
}
public ArrayList<String> getFinishNames() {
return m_finishNames;
}
public void setFinishTimes(ArrayList<Long> ar) {
m_finishTimes = ar;
}
public void setFinishNames(ArrayList<String> ar) {
m_finishNames = ar;
}
public boolean isRaceStarted() {
if (m_countDown != null) {
return m_countDown.isRaceStarted();
} else {
return false;
}
}
/////////////////////////////////////////
// Attributes
/////////////////////////////////////////
protected HashMap<String, WorldEntity> m_worldEntities;
protected ArrayList<WECar> m_weCars;
protected ArrayList<WECar> m_carsOrigin;
protected HashMap<String, Map> m_maps;
protected HashMap<String, Car> m_cars;
protected HashMap<String, DynamicObject> m_dynamicObjects;
protected boolean m_initialized;
protected String m_entityPlayer; //Key of the entity followed by the
protected Vector2D m_lastCameraPosition;
protected Vector2D m_cameraPosition;
protected WEMiniMap m_miniMap;
protected WECountdown m_countDown;
protected WEWrongDirection m_wrongDirection;
protected ItemController m_itemsController;
protected WEInformations m_informations;
protected WECounter m_counter;
protected ArrayList<String> m_entitiesList;
protected String m_mode;
protected long m_startTime;
protected boolean m_isUpdating;
protected String m_car;
protected int m_pos;
protected String m_map;
protected ArrayList<Integer> m_posList;
protected ArrayList<String> m_pseudoList;
protected ArrayList<String> m_idList;
protected ArrayList<String> m_carsList;
protected WECar m_trollEmitter;
protected boolean m_isTrolling;
protected long m_trollingTime;
protected ArrayList<Long> m_finishTimes;
protected ArrayList<String> m_arrivalOrder;
protected ArrayList<String> m_finishNames;
protected WERaceEnd m_raceEnd;
protected long m_tabTime;
protected HighScoreManager m_scoreManager;
protected ArrayList<Boolean> m_highScoreClient;
protected WECar m_originalCar;
protected long m_lastActionTimming;
protected Vector2D m_pausePosition;
}