2013年6月6日 星期四

【Java教學】半實裝 時空裂痕




src/l1j/server/Config.java

/** OtherSettings control */
public static short CrackStartTime;//時空裂痕開啟時間(單位分鐘)
public static short CrackOpenTime;//時空裂痕打開多久(單位分鐘)


CrackStartTime = Short.parseShort(otherSettings.getProperty(
"CrackStartTime", "6"));//時空裂痕開啟時間(單位分鐘)
CrackOpenTime = Short.parseShort(otherSettings.getProperty(
"CrackOpenTime", "90")); //時空裂痕打開多久(單位分鐘)


} else if (pName.equalsIgnoreCase("CrackStartTime")) {//時空裂痕開啟時間(單位每分)
CrackStartTime = Short.valueOf(pValue);
} else if (pName.equalsIgnoreCase("CrackOpenTime")) {//時空裂痕開放多久(單位分鐘)
CrackOpenTime = Short.valueOf(pValue);






src/l1j/server/server/GameServer.java


SystemMessage.getInstance(); // WilliamSystemMessage

下面加入
CrackTime.getStart();// 時空裂痕時間控制





src/l1j/server/server/model/L1World.java

宣告
private final Map<Integer, L1NpcInstance> _allNpcs;//全NPC 時空裂痕 城堡警衛

private L1World() {
_allPlayers = Maps.newConcurrentMap(); // 全てのプレイヤー
_allPets = Maps.newConcurrentMap(); // 全てのペット
_allSummons = Maps.newConcurrentMap(); // 全てのサモンモンスター
_allObjects = Maps.newConcurrentMap(); // 全てのオブジェクト(L1ItemInstance入り、L1Inventoryはなし)
_visibleObjects = new Map[MAX_MAP_ID + 1]; // マップ毎のオブジェクト(L1Inventory入り、L1ItemInstanceはなし)
_allWars = Lists.newConcurrentList(); // 全ての戦争
_allClans = Maps.newConcurrentMap(); // 全てのクラン(Online/Offlineどちらも)


for (int i = 0; i <= MAX_MAP_ID; i++) {
_visibleObjects[i] = Maps.newConcurrentMap();
}
}

找位置加入

_allNpcs = Maps.newConcurrentMap(); //全NPC 時空裂痕


public void storeObject(L1Object object) {
if (object == null) {
throw new NullPointerException();
}

下面加入

//全NPC 城堡警衛 時空裂痕
if (object instanceof L1NpcInstance) {
_allNpcs.put(object.getId(), (L1NpcInstance) object);
}
if (object instanceof L1PcInstance) {
_allPlayers.put(((L1PcInstance) object).getName(), (L1PcInstance) object);
}
if (object instanceof L1PetInstance) {
_allPets.put(object.getId(), (L1PetInstance) object);
}
if (object instanceof L1SummonInstance) {
_allSummons.put(object.getId(), (L1SummonInstance) object);
}
}


public void removeObject(L1Object object) {
if (object == null) {
throw new NullPointerException();
}


_allObjects.remove(object.getId());


下面加入

//全NPC 城堡警衛 時空裂痕
if (object instanceof L1NpcInstance) {
_allNpcs.remove(object.getId());
}
//全NPC 城堡警衛 end


public List<L1Object> getVisiblePoint(L1Location loc, int radius) {
List<L1Object> result = Lists.newList();
int mapId = loc.getMapId(); // ループ内で呼ぶと重いため

if (mapId <= MAX_MAP_ID) {
for (L1Object element : _visibleObjects[mapId].values()) {
if (mapId != element.getMapId()) {
continue;
}

if (loc.getTileLineDistance(element.getLocation()) <= radius) {
result.add(element);
}
}
}

return result;
}

下面加入

//全NPC 城堡警衛 時空裂痕
public List<L1NpcInstance> getVisibleNpc(L1Object object) {
return getVisibleNpc(object, -1);
}
public List<L1NpcInstance> getVisibleNpc(L1Object object, int radius) {
int map = object.getMapId();
Point pt = object.getLocation();
List<L1NpcInstance> result = Lists.newList();

for (L1NpcInstance element : _allNpcs.values()) {
if (element.equals(object)) {
continue;
}

if (map != element.getMapId()) {
continue;
}

if (radius == -1) {
if (pt.isInScreen(element.getLocation())) {
result.add(element);
}
} else {
if (pt.getTileLineDistance(element.getLocation()) <= radius) {
result.add(element);
}
}
}
return result;
}
//全NPC 城堡警衛 end


/**
* objectを認識できる範囲にいるプレイヤーを取得する
* @param object
* @return
*/
public List<L1PcInstance> getRecognizePlayer(L1Object object) {
return getVisiblePlayer(object, Config.PC_RECOGNIZE_RANGE);
}

下面加入

//全NPC 城堡警衛 時空裂痕
private Collection<L1NpcInstance> _allNpcValues;

public Collection<L1NpcInstance> getAllNpcs() {
Collection<L1NpcInstance> vs = _allNpcValues;
return (vs != null) ? vs : (_allNpcValues = Collections
.unmodifiableCollection(_allNpcs.values()));
}
//全NPC 城堡警衛 end




src/l1j/server/server/model/gametime/CrackTime.java
(整個複製)

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */
package l1j.server.server.model.gametime;

import java.lang.reflect.Constructor;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Logger;
import java.util.logging.Level;

import l1j.server.Config;
import l1j.server.server.GeneralThreadPool;
import l1j.server.server.IdFactory;
import l1j.server.server.datatables.NpcTable;
import l1j.server.server.model.L1World;
import l1j.server.server.model.L1Location;
import l1j.server.server.model.L1Object;
import l1j.server.server.model.L1Teleport;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.Instance.L1NpcInstance;
import l1j.server.server.serverpackets.S_CharVisualUpdate;
import l1j.server.server.serverpackets.S_MapID;
import l1j.server.server.serverpackets.S_OtherCharPacks;
import l1j.server.server.serverpackets.S_OwnCharPack;
import l1j.server.server.serverpackets.S_RemoveObject;
import l1j.server.server.serverpackets.S_Weather;
import l1j.server.server.templates.L1Npc;

/**
 * 時空裂痕 控制項時間軸
 */
public class CrackTime extends TimerTask {
private static Logger _log = Logger.getLogger(CrackTime.class.getName());
private Timer _timeHandler = new Timer(true);
private static Random _random = new Random();
private boolean _isOver = false;
// 時空裂痕已開始時間(1/2秒)
private int _startTime = 0;

private static final int[][] _crack = {
{ 32639, 32876, 780 }, //底比斯
{ 32794, 32751, 783 }  //提卡爾
};
private static final int[][] _crackLoc = {
{ 32728, 32709, 4 }, { 32848, 32639, 4 }, { 32852, 32705, 4 }, // 邪惡神殿
{ 32913, 33168, 4 }, { 32957, 33247, 4 }, { 32913, 33425, 4 }, // 沙漠綠洲
{ 34255, 33203, 4 }, { 34232, 33312, 4 }, { 34276, 33359, 4 }  // 黃昏山脈
};
private static CrackTime _instance;
public static CrackTime getStart() {
if (_instance == null) {
_instance = new CrackTime();
}
return _instance;
}
public void startCrackTime(){
CrackTime.getStart();
}
private CrackTime() {
// 開始執行此時間軸
_timeHandler.schedule(this, 500, 500);
// 交由線程工廠 處理
GeneralThreadPool.getInstance().execute(this);
}

@Override
public void run() {
// 時空裂痕結束
if (_isOver) {
try {
clear();
//時空裂痕開啟時間(單位小時) CrackStartTime*1小時(3600000)
//時空裂痕開啟時間(單位每分) CrackStartTime*1分鐘(60000)
Thread.sleep(Config.CrackStartTime*60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
_startTime ++;
switch (_startTime) {
case 600*2:// 時間軸開始至600秒時
L1World.getInstance().broadcastServerMessage("\\fV時空裂痕即將開啟.....");
break;
case 610*2:// 時空裂痕開啟至610秒時
spawnCrack();
break;
}
//時空裂痕開啟多久關閉(單位分鐘) 
if (_startTime >= Config.CrackOpenTime*60*2 + 240) {//當時間到達設定數,關閉
_isOver = true;
}
}
/**
 * 清空時空裂痕資訊(時空裂痕結束)
 */
private void clear() {
_startTime = 0;
_isOver = false;
L1World.getInstance().broadcastServerMessage("\\fY時空裂痕關閉了。");
for (L1Object obj : L1World.getInstance().getAllNpcs()) {
if (obj instanceof L1NpcInstance) {
L1NpcInstance Cracknpc = (L1NpcInstance) obj;
if (Cracknpc.getNpcId()== 71254) {
Cracknpc.deleteMe();
}
}
}
for(L1PcInstance pc : L1World.getInstance().getAllPlayers()){
if (pc.getMapId()==780 || pc.getMapId()==783){
if (pc.isDead()){
restartPlayer(pc,32616,32782,(short)4);
}else{
L1Teleport.teleport(pc,33442,32797,(short)4,5,true);//時空裂痕結束,傳送的地圖 預設奇岩
}
}
}
}

private void spawnCrack() {
L1Location crack = null;
L1Location crack_loc = null;
int rnd1 = _random.nextInt(2); // 補+1,讓隨機數1~2
int rnd2 = _random.nextInt(9); // 補+1,讓隨機數1~9
crack = new L1Location(_crack[rnd1][0], _crack[rnd1][1], _crack[rnd1][2]);
crack_loc = new L1Location(_crackLoc[rnd2][0], _crackLoc[rnd2][1], _crackLoc[rnd2][2]);
String msg = "";  
if (crack_loc.getX() == 32728 && crack_loc.getY() == 32709 || 
crack_loc.getX() == 32848 && crack_loc.getY() == 32639 ||
crack_loc.getX() == 32852 && crack_loc.getY() == 32705)//遠古戰場
msg = "遠古戰場"; 
else if (crack_loc.getX() == 32913 && crack_loc.getY() == 33168 || 
crack_loc.getX() == 32957 && crack_loc.getY() == 33247 ||
crack_loc.getX() == 32913 && crack_loc.getY() == 33425) //沙漠地區
msg = "沙漠地區";
else if (crack_loc.getX() == 34255 && crack_loc.getY() == 33203 || 
crack_loc.getX() == 34232 && crack_loc.getY() == 33312 ||
crack_loc.getX() == 34276 && crack_loc.getY() == 33359)//黃昏山脈
msg = "黃昏山脈";
L1World.getInstance().broadcastServerMessage("\\fV時空裂痕於《"+msg+"》附近開啟!!異界邪惡氣息瀰漫...");
createCrack(crack.getX(), crack.getY(), (short) crack.getMapId(), crack_loc.getX(), crack_loc.getY(), (short) crack_loc.getMapId());
createCrack(crack_loc.getX(), crack_loc.getY(), (short) crack_loc.getMapId(), crack.getX(), crack.getY(), (short) crack.getMapId());
}

private void createCrack(int x, int y, short mapId, int to_x, int to_y, short to_mapId) {
try {
L1Npc l1npc = NpcTable.getInstance().getTemplate(71254);

if (l1npc == null) {
return;
}

String s = l1npc.getImpl();
Constructor<?> constructor = Class.forName("l1j.server.server.model.Instance." + s + "Instance").getConstructors()[0];
Object aobj[] = { l1npc };
L1NpcInstance npc = (L1NpcInstance) constructor.newInstance(aobj);

npc.setId(IdFactory.getInstance().nextId());
npc.setX(x);
npc.setY(y);
npc.setMap(mapId);
npc.setHomeX(npc.getX());
npc.setHomeY(npc.getY());
npc.setHeading(0);

L1World.getInstance().storeObject(npc);
L1World.getInstance().addVisibleObject(npc);

Teleport teleport = new Teleport(npc, to_x, to_y, to_mapId);
GeneralThreadPool.getInstance().execute(teleport);
} catch (Exception e) {
_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
}
public void restartPlayer(L1PcInstance pc, int locx, int locy, short mapid){//移除玩家
pc.removeAllKnownObjects();
pc.broadcastPacket(new S_RemoveObject(pc));
pc.setCurrentHp(pc.getLevel());
pc.set_food(40);
pc.setDead(false);
pc.setStatus(0);
L1World.getInstance().moveVisibleObject(pc, mapid);
pc.setX(locx);
pc.setY(locy);
pc.setMap((short) mapid);
pc.sendPackets(new S_MapID(pc.getMapId(), pc.getMap().isUnderwater()));
pc.broadcastPacket(new S_OtherCharPacks(pc));
pc.sendPackets(new S_OwnCharPack(pc));
pc.sendPackets(new S_CharVisualUpdate(pc));
pc.startHpRegeneration();
pc.startMpRegeneration();
pc.sendPackets(new S_Weather(L1World.getInstance().getWeather()));
pc.stopPcDeleteTimer();
if (pc.getHellTime() > 0) {
pc.beginHell(false);
}
}

class Teleport implements Runnable {
private L1NpcInstance _npc = null;

private int _to_x = 0;
private int _to_y = 0;
private short _to_mapId = 0;

public Teleport(L1NpcInstance npc, int to_x, int to_y, short to_mapId) {
_npc = npc;
_to_x = to_x;
_to_y = to_y;
_to_mapId = to_mapId;
}

public void run() {
try {
Thread.sleep(1000);
for (;;) {
if (_npc._destroyed) {
return;
}

for (L1Object obj : L1World.getInstance().getVisiblePoint(_npc.getLocation(), 1)) {
if (obj instanceof L1PcInstance) {
L1PcInstance target = (L1PcInstance) obj;
L1Location tmp_loc = new L1Location(_to_x, _to_y, _to_mapId);
L1Location rnd_loc = tmp_loc.randomLocation(1, 5, false);
L1Teleport.teleport(target, rnd_loc.getX(), rnd_loc.getY(), (short) rnd_loc.getMapId(), target.getHeading(), true);
}
}
Thread.sleep(1000);
}
} catch (Exception e) {
_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
}
}
}








2 則留言:

  1. 快樂大~
    請問一下~
    我已經按照您的步驟將所有程式碼修改完成,也已經放進核心裡面了
    但是進入遊戲之後發現,訊息是會提示時空裂縫即將開啟的字樣,但是實際到了之後卻沒發現任何可以傳送的NPC
    而且並沒有辦法從Config裡面的檔案修改出現時間以及結束時間
    請問快樂大,還需要修改哪裡讓這支程式更加完整呢?
    有勞快樂大解惑...
    謝謝~

    回覆刪除
    回覆
    1. 對了!還有一點想要請教快樂大~
      這是一開服就有的問題
      就是只要遇到可以變身的怪物(如變形怪等等),或是使用變形魔杖將怪物變身,全畫面的玩家包含GM都會出現買賣物品的視窗
      但是只要將人物移動至看不到怪物後,再移回去,怪物就又變身了
      還請快樂大替小弟解決我真的找不到原因的BUG...
      感謝快樂大...

      刪除