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); } } } }