package games.mapacman.server;
import games.mapacman.common.Dot;
import games.mapacman.common.EatenSign;
import games.mapacman.common.Fruit;
import games.mapacman.common.Powerpill;
import games.mapacman.common.Superdot;
import games.mapacman.common.ZoneChangePoint;
import games.mapacman.common.consts;
import java.awt.Point;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Random;
import java.util.Vector;
import marauroa.common.game.RPObject;
import marauroa.server.game.MarauroaRPZone;
public class MaPacmanZone extends MarauroaRPZone {
private int x;
private int y;
private boolean[][] collision;
private String zonename;
private MaPacmanRPWorld world;
private Dot[][] dots;
private Vector <RPObject> Ghosts;
private Vector<Dot> respawnDots;
private Vector<RPObject> Players;
private Vector<Point> RespawnPoints;
private Vector<Point> GhostRespawnPoints;
private Vector<Point> GhostBlock;
private Vector<EatenSign> EatenSigns;
private Vector<ZoneChangePoint> zoneChangePoints;
private Vector<String> zoneChangeNames;
private Vector<zoneChangeNote> zoneChangeNotes;
private Vector<RPObject> addMovablesNextTurn;
private Random randomgen;
private int dot_respawnTime = 150;
private int superdot_respawnTime = 350;
private int fruit_respawnTime = 500;
private int powerpill_respawnTime = 700;
private int dot_score=1;
private int superdot_score=5;
private int fruit_score=50;
private int powerpill_score=0;
// Probability that SuperDot is Superdot ... otherwise it's normal dot
// prob=1 means every sdot is superdot ... prob =3 means every third Sdot is Sdot
private int superdot_prob=1;
private int fruit_prob=30;
private int powerpill_prob=1;
public MaPacmanZone(String zoneName, MaPacmanRPWorld world) {
super(zoneName);
this.randomgen = world.getRandom();
this.Ghosts = new Vector<RPObject>();
this.addMovablesNextTurn = new Vector<RPObject>();
this.respawnDots = new Vector<Dot>();
this.Players = new Vector<RPObject>();
this.RespawnPoints = new Vector<Point>();
this.GhostRespawnPoints = new Vector<Point>();
this.GhostBlock = new Vector<Point>();
this.EatenSigns = new Vector<EatenSign>();
this.zoneChangeNames = new Vector<String>();
this.zoneChangePoints= new Vector<ZoneChangePoint>();
// save zoneChanges here to do when turn ends
this.zoneChangeNotes= new Vector<zoneChangeNote>();
this.zonename=zoneName;
this.world=world;
world.addRPZone(this);
}
public void initialize()
{ /*
# Wall
* Dot
g Ghost without Dot
G Ghost with Dot
r respawn without Dot
R respawn with Dot
F Fruit
P Powerpill
0 to 9 ZoneChange Points
- Block without Dot
_ Block with Dot
+ Superdot
*/
try
{
BufferedReader map = new BufferedReader(new FileReader("games/mapacman/server/maps/"+zonename+".map"));
int x=100;
int y =100;
boolean mapstart=false;
String line;
int ypos=0;
while( (line = map.readLine()) !=null )
{
if (mapstart)
{
for (int xpos=0; xpos<line.length();xpos++)
{
char currentItem =line.charAt(xpos);
if (currentItem =='#')
{ // is WALL
collision[xpos][ypos]=true;
RPObject wall = new RPObject(RPObject.INVALID_ID);
wall.put("type",consts.TYPE_WALL);
wall.put("x",xpos);
wall.put("y",ypos);
wall.put("zoneid",this.zonename);
world.add(wall);
}
else
{ // NO WALL
collision[xpos][ypos]=false;
if (currentItem =='G' || currentItem =='g' )
{ // is GHOST
if (currentItem =='G') currentItem='*';
RPObject ghost = new RPObject(RPObject.INVALID_ID);
ghost.put("type",consts.TYPE_GHOST);
ghost.put("x",xpos);
ghost.put("y",ypos);
ghost.put("dir",consts.DIR_NORTH);
ghost.put("nextdir",consts.DIR_NORTH);
ghost.put("!changedir",10);
ghost.put("zoneid",this.zonename);
ghost.put("color",randomgen.nextInt(4));
Ghosts.add(ghost);
world.add(ghost);
GhostRespawnPoints.add(new Point(xpos,ypos));
}
else if (currentItem =='R' || currentItem =='r' )
{ // is RespawnPoint
if (currentItem =='R') currentItem='*';
RespawnPoints.add(new Point(xpos,ypos));
}
else if (currentItem =='-' || currentItem =='_' )
{ // is GhostBlock
if (currentItem =='_') currentItem='*';
GhostBlock.add(new Point(xpos,ypos));
}
else if (currentItem =='+')
{ // is SuperDot
Dot sdot = new Superdot(xpos,ypos,dot_score,superdot_score,superdot_prob,this);
dots[xpos][ypos]= sdot;
world.add(sdot.getRPObject());
}
else if (currentItem =='P')
{ // is Powerpill
Dot pill = new Powerpill(xpos,ypos,dot_score,powerpill_score,powerpill_prob,this);
dots[xpos][ypos]= pill;
world.add(pill.getRPObject());
}
else if (currentItem =='F')
{ // is Fruit
Dot fruit = new Fruit(xpos,ypos,dot_score,fruit_score,fruit_prob,this);
dots[xpos][ypos]= fruit;
world.add(fruit.getRPObject());
}
//check for Dot at last because other Items can have Dot below
if (currentItem =='*')
{ // is DOT
Dot dot = new Dot(xpos,ypos,dot_score,this);
dots[xpos][ypos]= dot;
world.add(dot.getRPObject());
}
else
{ // ZoneChange Point
if (currentItem>=48 && currentItem<=57)
{
ZoneChangePoint point = new ZoneChangePoint(this,zoneChangeNames.get(currentItem-48),xpos,ypos);
zoneChangePoints.add(point);
world.add(point.getRPObject());
}
}
}
}
ypos++;
}
else // MAP INFO didn't start yet
{
if(line.startsWith("x="))
{
x=Integer.parseInt(line.substring(2));
}
else if(line.startsWith("y="))
{
y=Integer.parseInt(line.substring(2));
}
else if(line.startsWith("y="))
{
y=Integer.parseInt(line.substring(2));
}
else if(line.startsWith("dot_respawnTime="))
{
dot_respawnTime=Integer.parseInt(line.substring("dot_respawnTime=".length()));
}
else if(line.startsWith("superdot_respawnTime="))
{
superdot_respawnTime=Integer.parseInt(line.substring("superdot_respawnTime=".length()));
}
else if(line.startsWith("fruit_respawnTime="))
{
fruit_respawnTime=Integer.parseInt(line.substring("fruit_respawnTime=".length()));
}
else if(line.startsWith("powerpill_respawnTime="))
{
powerpill_respawnTime=Integer.parseInt(line.substring("powerpill_respawnTime=".length()));
}
else if(line.startsWith("dot_Score="))
{
dot_score=Integer.parseInt(line.substring("dot_Score=".length()));
}
else if(line.startsWith("superdot_Score="))
{
superdot_score=Integer.parseInt(line.substring("superdot_Score=".length()));
}
else if(line.startsWith("fruit_Score="))
{
fruit_score=Integer.parseInt(line.substring("fruit_Score=".length()));
}
else if(line.startsWith("powerpill_Score="))
{
powerpill_score=Integer.parseInt(line.substring("powerpill_Score=".length()));
}
else if(line.startsWith("mapchange="))
{
zoneChangeNames.add(line.substring("mapchange=".length()));
}
else if(line.startsWith("superdot_probability="))
{
superdot_prob=Integer.parseInt(line.substring("superdot_probability=".length()));
}
else if(line.startsWith("fruit_probability="))
{
fruit_prob=Integer.parseInt(line.substring("fruit_probability=".length()));
}
else if(line.startsWith("powerpill_probability="))
{
powerpill_prob=Integer.parseInt(line.substring("powerpill_probability=".length()));
}
else if(line.startsWith("MAPSTART"))
{
mapstart=true;
collision = new boolean[x][y];
dots = new Dot[x][y];
}
}
}
}
catch (Exception e)
{
//TODO: throw the exception to the caller so it knows about the problem.
e.printStackTrace();
}
}
@Override
public void onInit() throws Exception {
System.out.println("init zone :"+zonename);
}
@Override
public void onFinish() throws Exception {
// TODO Auto-generated method stub
}
public int isCollision(int x, int y) {
// order is important : GhostBlock needs to be higher than Player
if (collision[x][y]) return consts.COLLISION_WALL;
for (Point block : GhostBlock)
{
if(block.getX()==x && block.getY()==y) return consts.COLLISION_GHOSTBLOCK;
}
for(RPObject player : Players)
{
if(player.getInt("x")==x && player.getInt("y")==y ) return consts.COLLISION_PLAYER;
}
for(RPObject ghost : Ghosts)
{
if(ghost.getInt("x")==x && ghost.getInt("y")==y ) return consts.COLLISION_GHOST;
}
return consts.COLLISION_NONE;
}
public Dot eatDot(int x, int y) {
if (dots[x][y]!= null)
{
Dot res = dots[x][y];
dots[x][y] = null;
return res;
}
return null;
}
public void respawnDot(Dot object) {
dots[object.getX()][object.getY()] = object;
}
public Point getFreeRespawnPoint(int type)
{
Random random = new Random();
for (int i=0;i<RespawnPoints.size();i++)
{
Point point;
// type = 0 is Player
if (type == 0) point = RespawnPoints.get(random.nextInt(RespawnPoints.size()));
else point = GhostRespawnPoints.get(random.nextInt(GhostRespawnPoints.size()));
boolean free = true;
for (RPObject player : Players)
{
if (player.getInt("x")== point.getX() && player.getInt("y")==point.getY())
{
free = false;
break;
}
}
for (RPObject ghost : Ghosts)
{
if (ghost.getInt("x")== point.getX() && ghost.getInt("y")==point.getY())
{
free = false;
break;
}
}
if (free) return point;
}
// if we are here, no free RespawnPoint has been found
return null;
}
public boolean addPlayer(RPObject object)
{
boolean res = respawnMovable(object);
if (res)
Players.add(object);
return res;
}
private boolean respawnMovable(RPObject object) {
Point respawnPoint = getFreeRespawnPoint(object.get("type").equals(consts.TYPE_PLAYER) ? 0 : 1);
if (respawnPoint!=null)
{
object.put("x",(int)respawnPoint.getX());
object.put("y",(int)respawnPoint.getY());
object.put("dir",consts.DIR_NONE);
object.put("nextdir",consts.DIR_NONE);
object.put("zoneid",this.zonename);
return true;
}
else
{
// try to add Player in next Turn
addMovablesNextTurn.add(object);
return false;
}
}
public void beginTurn()
{
// check for Dots to respawn
Vector<Dot> deleteDots = new Vector<Dot>();
for(Dot dot: respawnDots)
{
if (dot.respawn())
{ // add dot to Vector to delete later - can't delete while in for()
deleteDots.add(dot);
respawnDot(dot);
world.modify(dot.getRPObject());
}
}
// delete respawned Dots from Vector
for(Dot object: deleteDots)
{
respawnDots.remove(object);
}
// move Players and Ghosts
movePlayers();
moveGhosts();
// change Zones
for(zoneChangeNote note : zoneChangeNotes)
{
world.changeZone(note.object,this, note.newZone.getZoneName());
}
zoneChangeNotes.clear();
// add Players that could not been added
Vector<RPObject> temp = new Vector<RPObject>();
for (RPObject movable: addMovablesNextTurn)
{
respawnMovable(movable);
}
addMovablesNextTurn.clear();
for (RPObject player: temp)
{
addPlayer(player);
}
Vector<EatenSign> signtemp = new Vector<EatenSign>();
// check EatenSigns
for (EatenSign sign : EatenSigns)
{
if (sign.checkDelete())
{
world.remove(sign.getRPObject().getID());
signtemp.add(sign);
}
}
for (EatenSign sign : signtemp)
{
EatenSigns.remove(sign);
}
}
public void movePlayers()
{
for(RPObject object: Players)
{
// if Player is in powermode reduce powerturntime
if (object.getInt("power")>0)
object.put("power",object.getInt("power")-1);
int nextDir = object.getInt("nextdir");
int dir = object.getInt("dir");
if (nextDir!=consts.DIR_NONE)
{
int collision = consts.COLLISION_NONE;
int x = object.getInt("x");
int y = object.getInt("y");
switch(nextDir)
{
case consts.DIR_NORTH : collision = isCollision(x,y-1); break;
case consts.DIR_SOUTH : collision = isCollision(x,y+1); break;
case consts.DIR_EAST : collision = isCollision(x+1,y); break;
case consts.DIR_WEST : collision = isCollision(x-1,y); break;
}
if (collision == consts.COLLISION_NONE || collision == consts.COLLISION_GHOSTBLOCK)
{
object.put("dir",nextDir);
dir=nextDir;
object.put("nextdir",consts.DIR_NONE);
}
else
{
// if Player is not moving and want to move in a direction which is blocked. Stop all movements
if(dir==consts.DIR_NONE)
{
object.put("nextdir",consts.DIR_NONE);
object.put("dir",consts.DIR_NONE);
}
}
}
switch(dir)
{
case consts.DIR_NORTH : movePlayer(object,0,-1); break;
case consts.DIR_SOUTH : movePlayer(object,0,1); break;
case consts.DIR_EAST : movePlayer(object,1,0); break;
case consts.DIR_WEST : movePlayer(object,-1,0); break;
case consts.DIR_NONE : movePlayer(object,0,0); break;
}
world.modify(object);
}
}
private void movePlayer(RPObject object, int x, int y)
{
int collisionType = isCollision(object.getInt("x")+x,object.getInt("y")+y);
int newX = object.getInt("x")+x;
int newY = object.getInt("y")+y;
// if no movement or no collision
if ( (x==0 && y==0) || collisionType == consts.COLLISION_NONE || collisionType == consts.COLLISION_GHOSTBLOCK)
{
Dot dot;
if ((dot=eatDot(newX,newY))!=null)
{
dot.eaten(object);
dot.addStats(world.getStats());
object.put("score",object.getInt("score")+dot.getScore());
dot.setRespawnTime();
respawnDots.add(dot);
world.modify(dot.getRPObject());
}
else
{
for (ZoneChangePoint zonechange : zoneChangePoints)
{
if (zonechange.isPlacedAt(newX,newY))
{ // add to change Zone atfer turn
zoneChangeNotes.add(new zoneChangeNote(object,zonechange));
}
}
}
object.put("x",newX);
object.put("y",newY);
}
else
{
switch (collisionType)
{
case consts.COLLISION_WALL :
case consts.COLLISION_PLAYER : object.put("dir",consts.DIR_NONE);break;
case consts.COLLISION_GHOST :
if (object.getInt("power")>0)
{ // Player is in Powermode
object.put("x",newX);
object.put("y",newY);
killGhostAt(newX,newY);
Dot dot;
if ((dot=eatDot(newX,newY))!=null)
{
dot.eaten(object);
dot.addStats(world.getStats());
object.put("score",object.getInt("score")+dot.getScore());
dot.setRespawnTime();
respawnDots.add(dot);
world.modify(dot.getRPObject());
}
}
else
{
object.put("x",newX);
object.put("y",newY);
world.modify(object);
killPlayer(object);
break;
}
}
}
world.modify(object);
}
private void killGhostAt(int newX, int newY) {
for (RPObject ghost : Ghosts)
{
if (ghost.getInt("x")== newX && ghost.getInt("y")== newY)
killGhost(ghost);
}
}
private void killGhost(RPObject object) {
world.getStats().add("killed Ghost",1);
EatenSign sign = new EatenSign(object.getInt("x"),object.getInt("y"),this);
EatenSigns.add(sign);
world.add(sign.getRPObject());
respawnMovable(object);
}
private void killPlayer(RPObject object) {
int x = object.getInt("x");
int y = object.getInt("y");
world.getStats().add("killed Player",1);
int score = object.getInt("score");
int newPlayerScore = (int)(score-score/10);
// if more than 200 Points are lost ... only take 200
if (newPlayerScore<score-200) newPlayerScore = score-200;
object.put("score",newPlayerScore);
respawnMovable(object);
object.put("dir",consts.DIR_NONE);
world.modify(object);
EatenSign sign = new EatenSign(x,y,this);
EatenSigns.add(sign);
world.add(sign.getRPObject());
}
public void moveGhosts()
{
// save CPU ?? don't move ghosts when no Player in world
if (!world.moveGhosts())
return;
for (RPObject ghost : Ghosts)
{
// check if Ghost should change Direction
if (ghost.getInt("!changedir")==0)
{
ghost.put("dir",randomgen.nextInt(4));
ghost.put("!changedir",randomgen.nextInt(6)+1);
}
else
{
ghost.put("!changedir",ghost.getInt("!changedir")-1);
}
// move Ghost
int nextDir = ghost.getInt("nextdir");
if (nextDir!=consts.DIR_NONE)
{
int collision = consts.COLLISION_NONE;
int x = ghost.getInt("x");
int y = ghost.getInt("y");
switch(nextDir)
{
case consts.DIR_NORTH : collision = isCollision(x,y-1); break;
case consts.DIR_SOUTH : collision = isCollision(x,y+1); break;
case consts.DIR_EAST : collision = isCollision(x+1,y); break;
case consts.DIR_WEST : collision = isCollision(x-1,y); break;
}
if (collision == consts.COLLISION_NONE || collision == consts.COLLISION_PLAYER)
{
ghost.put("dir",nextDir);
ghost.put("nextdir",consts.DIR_NONE);
}
}
switch(ghost.getInt("dir"))
{
case consts.DIR_NORTH : moveGhost(ghost,0,-1); break;
case consts.DIR_SOUTH : moveGhost(ghost,0,1); break;
case consts.DIR_EAST : moveGhost(ghost,1,0); break;
case consts.DIR_WEST : moveGhost(ghost,-1,0); break;
}
world.modify(ghost);
}
}
private void moveGhost(RPObject ghost, int x, int y) {
int collisionType = isCollision(ghost.getInt("x")+x,ghost.getInt("y")+y);
if (collisionType == consts.COLLISION_NONE || collisionType == consts.COLLISION_PLAYER )
{
int newX = ghost.getInt("x")+x;
int newY = ghost.getInt("y")+y;
ghost.put("x",newX);
ghost.put("y",newY);
if (collisionType==consts.COLLISION_PLAYER)
{
for (RPObject player : Players)
{
if (player.getInt("x")==newX && player.getInt("y")==newY)
{
if (player.getInt("power")>0)
{ // Player is in Powermode
ghost.put("x",newX);
ghost.put("y",newY);
world.modify(ghost);
killGhostAt(newX,newY);
}
else
{
killPlayer(player);
break;
}
break;
}
}
}
}
else
{
ghost.put("!changedir",0);
}
}
public void removePlayer(RPObject player) {
Players.remove(player);
}
public String getName()
{
return zonename;
}
public Vector<RPObject> getPlayers() {
return Players;
}
public boolean hasPlayers() {
return (getPlayers().size()>0);
}
public int getDotRespawnTime() {
return dot_respawnTime;
}
public int getSuperDotRespawnTime() {
return superdot_respawnTime;
}
public Random getRandom() {
return randomgen;
}
public int getPowerpillRespawnTime() {
return powerpill_respawnTime;
}
public int getFruitRespawnTime() {
return fruit_respawnTime;
}
public MaPacmanRPWorld getWorld() {
return world;
}
}
class zoneChangeNote
{
ZoneChangePoint newZone;
RPObject object;
public zoneChangeNote(RPObject object, ZoneChangePoint newZone)
{
this.newZone = newZone;
this.object = object;
}
}