package module.battle;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import module.character.CharList;
import module.character.Group;
import module.character.GroupList;
import module.character.PlayerGroup;
import module.character.api.ICharacter;
import module.character.api.IntPair;
import module.character.constants.CConfig.config;
import module.character.constants.CStatus.status;
import module.command.CommandServer;
import module.utility.EnDecoder;
import module.utility.ItemUtil;
public class BattleTask extends TimerTask {
protected GroupList team1List;
protected GroupList team2List;
private ConcurrentHashMap<ICharacter, IntPair> timeMap;
protected ArrayList<ICharacter> ready;
protected Timer battleTimer;
private int updateCounter = 0;
protected boolean isBlocked = false; // used if there's something need to pause the timer
public BattleTask(Group team1, Group team2) {
team1.setInBattle(true);
team2.setInBattle(true);
this.team1List = new GroupList();
this.team2List = new GroupList();
this.team1List.gList.add(team1);
this.team2List.gList.add(team2);
team1.setBattleTask(this);
team2.setBattleTask(this);
timeMap = new ConcurrentHashMap<ICharacter, IntPair>();
addTimeMap(team1);
addTimeMap(team2);
battleTimer = new Timer();
battleTimer.schedule(this, 0, 100);
}
public void addBattleGroup(Group addSide, Group targetG) {
GroupList side;
if (team1List.gList.contains(addSide))
side = this.team1List;
else
side = this.team2List;
targetG.setInBattle(true);
side.gList.add(targetG);
targetG.setBattleTask(this);
addTimeMap(targetG);
}
public void addBattleOppositeGroup(Group opposite, Group targetG){
GroupList side;
if (team1List.gList.contains(opposite))
side = this.team2List;
else
side = this.team1List;
targetG.setInBattle(true);
side.gList.add(targetG);
targetG.setBattleTask(this);
addTimeMap(targetG);
}
public void removeBattleGroup(Group g){
GroupList side;
if (team1List.gList.contains(g)) side = this.team1List;
else side = this.team2List;
if (g instanceof PlayerGroup){
for (Group gg : this.getEnemyGroups(g).gList){
gg.getAtRoom().informRoom(
String.format("�ѩ����h���a����A%s�h��j���A�^�_��̨Ϊ��A!\n", gg.getChiName()));
gg.recoverGroup();
}
}
side.gList.remove(g);
g.setInBattle(false);
g.setBattleTask(null);
this.removeGroupFromTimeMap(g);
if (side.gList.size() == 0)
checkBattleEnd();
}
public void run() {
if (isBlocked) return;
synchronized (this) {
ready = updateTime();
updatePlayerStatus();
}
updatePlayerStatus(team1List.gList);
updatePlayerStatus(team2List.gList);
try {
for (ICharacter c : ready) {
if (c.getMyGroup() instanceof PlayerGroup) {
if (((PlayerGroup) c.getMyGroup()).getConfigData().get(
config.REALTIMEBATTLE)) {
// real time battle
} else {
// blocks when a character in player's group is ready
try {
synchronized (this) {
wait();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
else c.battleAction(getEnemyGroups(c));
}
} catch (NullPointerException e) {
return; // no one is ready, return
}
}
protected void updatePlayerStatus(List<Group> groupList) {
for (Group g : groupList) {
if (g instanceof PlayerGroup) {
String output = "status:" + showPlayerStatus(g);
output = EnDecoder.encodeChangeLine(output);
EnDecoder.sendUTF8Packet(((PlayerGroup) g).getOutToClient(),
output);
}
}
}
private String showPlayerStatus(Group g) {
StringBuilder buffer = new StringBuilder();
int count = 1;
synchronized (timeMap) {
for (CharList cList : g.list) {
for (ICharacter c : cList.charList) {
double percentage = (double) timeMap.get(c).getCurrent()
/ (double) timeMap.get(c).getMax() * 100.0;
buffer.append(String.format("%d%%\tNo. %d %s\n",
(int) percentage, count, c.showStatus()));
count++;
}
}
}
return buffer.toString();
}
public void updatePlayerStatus(PlayerGroup g){
String output = "status:" + showPlayerStatus(g);
output = EnDecoder.encodeChangeLine(output);
EnDecoder.sendUTF8Packet(g.getOutToClient(),
output);
}
private void addTimeMap(Group newGroup) {
for (CharList cList : newGroup.list) {
for (ICharacter c : cList.charList) {
timeMap.put(c, new IntPair(0, c.getStatus(status.SPEED))); // temp assign = 3000
}
}
}
public GroupList getEnemyGroups(ICharacter c) {
if (team1List.gList.contains(c.getMyGroup()))
return team2List;
else
return team1List;
}
public GroupList getEnemyGroups(Group g) {
if (team1List.gList.contains(g))
return team2List;
else
return team1List;
}
public GroupList getMyGroups(ICharacter c) {
if (team1List.gList.contains(c.getMyGroup()))
return team1List;
else
return team2List;
}
protected ArrayList<ICharacter> updateTime() {
// update the battle time per 100ms
ArrayList<ICharacter> readyList = new ArrayList<ICharacter>();
int max, current;
synchronized (timeMap) {
for (Entry<ICharacter, IntPair> entry : timeMap.entrySet()) {
if (entry.getKey().isDown())
continue;
current = entry.getValue().getCurrent();
max = entry.getValue().getMax();
if (current >= max)
readyList.add(entry.getKey());
else if (current + 100 >= max) {
readyList.add(entry.getKey());
entry.getValue().setCurrent(current + 100);
} else
entry.getValue().setCurrent(current + 100);
/*
* if (current >= max) readyList.add(entry.getKey()); else
* entry.getValue().setCurrent(current + 100);
*/
}
if (readyList.size() == 0)
return null;
else
return readyList;
}
}
protected void updatePlayerStatus() {
updateCounter++;
if (updateCounter == 20) {
updateCounter = 0;
for (Group g : team1List.gList)
g.updateTime();
for (Group g : team2List.gList)
g.updateTime();
}
}
public void resetBattleTime(ICharacter c) {
synchronized (timeMap) {
IntPair target = timeMap.get(c);
target.setCurrent(0);
}
}
public ConcurrentHashMap<ICharacter, IntPair> getTimeMap() {
return this.timeMap;
}
public void checkBattleEnd() {
boolean over = false;
GroupList aliveGroups = null;
if (checkGroupListDown(team1List)) {
over = true;
aliveGroups = team2List;
} else if (checkGroupListDown(team2List)){
over = true;
aliveGroups = team1List;
}
if (over == true) {
// inform room that battle is end
aliveGroups.gList.get(0).getAtRoom().informRoom("������!\n");
// free the battle resources
battleTimer.cancel();
for (Group g : team1List.gList) {
g.setInBattle(false);
g.setBattleTask(null);
if (g instanceof PlayerGroup)
CommandServer.informGroup(g,
"status:" + ((PlayerGroup) g).showGroupStatus());
}
for (Group g : team2List.gList) {
g.setInBattle(false);
g.setBattleTask(null);
if (g instanceof PlayerGroup)
CommandServer.informGroup(g,
"status:" + ((PlayerGroup) g).showGroupStatus());
}
}
}
protected boolean checkGroupListDown(GroupList list) {
boolean allDown = true;
boolean groupDown;
boolean isDown = false;
while (!isDown) {
isDown = true;
for (Group g : list.gList) {
groupDown = true;
for (CharList cList : g.list) {
for (ICharacter c : cList.charList) {
if (!c.isDown()) {
allDown = false;
groupDown = false;
}
}
}
if (groupDown) {
if (g instanceof PlayerGroup) {
// TODO: implement player group dead action
CommandServer.informGroup(g, "�A����������F...\n");
removeBattleGroup(g);
g.getAtRoom().getGroupList().gList.remove(g);
CommandServer.informGroup(g, "�]���O�оǥ��ȡA�N�����ǰe�A�^�_�l��m�a�C\n");
CommandServer.informGroup(g, "�i�H�C�C���x���ˬ��U�ӳ�!\n");
g.recoverGroup();
g.setAtRoom(g.getInitialRoom());
g.getAtRoom().getGroupList().gList.add(g);
String out = "status:" + ((PlayerGroup) g).showGroupStatus();
CommandServer.informGroup(g, out);
return true;
} else {
ItemUtil.createLootingItem(g);
// group inventory drop to the ground
ItemUtil.dropAllItemOnDefeat(g);
// do group down event if there's any
GroupList oppositeGroups = getEnemyGroups(g);
PlayerGroup pg = null;
for (Group px : oppositeGroups.gList){
if (px instanceof PlayerGroup){
pg = (PlayerGroup) px;
break;
}
}
if (pg != null){
this.isBlocked = true;
g.list.get(0).charList.get(0).doEventWhenGroupDown(pg);
this.isBlocked = false;
}
}
// a group is down, remove data from this battle
removeGroupFromTimeMap(g);
g.getAtRoom().getGroupList().gList.remove(g);
g.setAtRoom(null);
g.setInBattle(false);
g.setBattleTask(null);
list.gList.remove(g);
isDown = false;
break;
}
}
}
return allDown;
}
protected void removeGroupFromTimeMap(Group g) {
for (CharList cList : g.list) {
for (ICharacter c : cList.charList) {
this.timeMap.remove(c);
}
}
}
}