2013年5月15日 星期三

【Java教學】計時地圖

by 浪漫物語網路社區 psnnwe 

1.
MapsTable.java DB化最大停留時間


尋找 MapData

增加

/**
  * 計時地圖時間
  */
public int maptime;

尋找 loadMapsFromDatabase

增加

data.maptime = rs.getInt("maptime");

找個地方增加

/**
  * 取回計時地圖時間
  * 
  * @param mapId
  * @return
  */
public int getMapTime(final int mapId) {
  final MapData map = this._maps.get(mapId);
  if (map == null) {
   return 0;
  }
  return this._maps.get(mapId).maptime;
}

mapids.sql  增加一個 maptime欄位(單位是分鐘)

2.
L1PcIntance.java 製作欄位來儲存秒數
找個地方增加


/**
  * 奇岩地監可停留時間(秒).
  */
private int _rocksPrisonTime;
/**
  * 取回奇岩地監可停留時間(秒).
  * 
  * @return
  */
public int getRocksPrisonTime() {
  return this._rocksPrisonTime;
}
/**
  * 設定奇岩地監使用時間.
  * 
  * @param time
  *            時間
  */
public void setRocksPrisonTime(final int time) {
  this._rocksPrisonTime = time;
}
/**
  * 拉斯塔巴德地監可停留時間(秒).
  */
private int _lastabardTime;
/**
  * 取回拉斯塔巴德地監可停留時間(秒).
  * 
  * @return
  */
public int getLastabardTime() {
  return this._lastabardTime;
}
/**
  * 設定拉斯塔巴德監獄使用時間.
  * 
  * @param time
  *            時間
  */
public void setLastabardTime(final int time) {
  this._lastabardTime = time;
}

/**
  * 象牙塔可停留時間(秒).
  */
private int _ivorytowerTime;
/**
  * 取回象牙塔可停留時間(秒).
  * 
  * @return
  */
public int getIvoryTowerTime() {
  return this._ivorytowerTime;
}
/**
  * 設定象牙塔使用時間.
  * 
  * @param time
  *            時間
  */
public void setIvoryTowerTime(final int time) {
  this._ivorytowerTime = time;
}

/**
  * 取回計時地圖使用時間
  * 
  * @param mapid
  *            玩家所在的地圖
  * @return
  */
public int getMapUseTime(final int mapid) {
  int result = 0;
  switch (mapid) {
  case 53: // 奇岩地監1F
  case 54: // 奇岩地監2F
  case 55: // 奇岩地監3F
  case 56: // 奇岩地監4F
   result = this._rocksPrisonTime;
   break;
  case 75: // 象牙塔1F
  case 76: // 象牙塔2F
  case 77: // 象牙塔3F
  case 78: // 象牙塔4F
  case 79: // 象牙塔5F
  case 80: // 象牙塔6F
  case 81: // 象牙塔7F
  case 82: // 象牙塔8F
   result = this._ivorytowerTime;
   break;
  case 450: // 拉斯塔巴德正門
  case 451: // 1樓 集會場
  case 452: // 1樓 突擊隊訓練場
  case 453: // 1樓 魔獸君王之室
  case 454: // 1樓 魔獸調教場
  case 455: // 1樓 魔獸訓練場
  case 456: // 1樓 魔獸召喚室
  case 460: // 2樓 黑魔法修練場
  case 462: // 2樓 法令軍王之室
  case 463: // 2樓 法令軍王的書房
  case 464: // 2樓 暗黑精靈召喚室
  case 465: // 2樓 暗黑精靈棲息地
  case 466: // 2樓 暗黑精靈研究室
  case 470: // 3樓 惡靈祭壇
  case 471: // 3樓 惡靈之主祭壇
  case 472: // 3樓 傭兵訓練場
  case 473: // 3樓 冥法軍訓練場
  case 474: // 3樓 歐姆實驗室
  case 475: // 3樓 冥法軍王之室
  case 476: // 3樓 中央控制室
  case 477: // 3樓 惡靈之主傭兵室
  case 478: // 3樓 控制室走廊
  case 490: // 地下訓練場
  case 491: // 地下通道
  case 492: // 暗殺軍王之室
  case 493: // 地下控制室
  case 494: // 地下處刑場
  case 495: // 地下競技場
  case 496: // 地下監獄
  case 530: // 4樓 格蘭肯神殿、長老.琪娜之室
  case 531: // 4樓 長老.巴塔斯之室、長老.安迪斯之室
  case 532: // 4樓 庭園廣場、長老.泰瑪斯之室
  case 533: // 4樓 長老.泰瑪斯之室、長老.拉曼斯之室、長老.巴陸德之室
  case 534: // 4樓 長老會議廳、副神官.卡山德拉之室、真.冥皇丹特斯之室
   result = this._lastabardTime;
   break;
  }
  return result;
}
/**
  * 設定地圖已使用時間.
  * 
  * @param time
  *            時間
  */
public void setMapUseTime(final int mapid, final int time) {
  switch (mapid) {
  case 53:// 奇岩地監1F
  case 54:// 奇岩地監2F
  case 55:// 奇岩地監3F
  case 56:// 奇岩地監4F
   this.setRocksPrisonTime(time);
   break;
  case 75:// 象牙塔1F
  case 76:// 象牙塔2F
  case 77:// 象牙塔3F
  case 78:// 象牙塔4F
  case 79:// 象牙塔5F
  case 80:// 象牙塔6F
  case 81:// 象牙塔7F
  case 82:// 象牙塔8F
   this.setIvoryTowerTime(time);
   break;
  case 450: // 拉斯塔巴德正門
  case 451: // 1樓 集會場
  case 452: // 1樓 突擊隊訓練場
  case 453: // 1樓 魔獸君王之室
  case 454: // 1樓 魔獸調教場
  case 455: // 1樓 魔獸訓練場
  case 456: // 1樓 魔獸召喚室
  case 460: // 2樓 黑魔法修練場
  case 462: // 2樓 法令軍王之室
  case 463: // 2樓 法令軍王的書房
  case 464: // 2樓 暗黑精靈召喚室
  case 465: // 2樓 暗黑精靈棲息地
  case 466: // 2樓 暗黑精靈研究室
  case 470: // 3樓 惡靈祭壇
  case 471: // 3樓 惡靈之主祭壇
  case 472: // 3樓 傭兵訓練場
  case 473: // 3樓 冥法軍訓練場
  case 474: // 3樓 歐姆實驗室
  case 475: // 3樓 冥法軍王之室
  case 476: // 3樓 中央控制室
  case 477: // 3樓 惡靈之主傭兵室
  case 478: // 3樓 控制室走廊
  case 490: // 地下訓練場
  case 491: // 地下通道
  case 492: // 暗殺軍王之室
  case 493: // 地下控制室
  case 494: // 地下處刑場
  case 495: // 地下競技場
  case 496: // 地下監獄
  case 530: // 4樓 格蘭肯神殿、長老.琪娜之室
  case 531: // 4樓 長老.巴塔斯之室、長老.安迪斯之室
  case 532: // 4樓 庭園廣場、長老.泰瑪斯之室
  case 533: // 4樓 長老.泰瑪斯之室、長老.拉曼斯之室、長老.巴陸德之室
  case 534: // 4樓 長老會議廳、副神官.卡山德拉之室、真.冥皇丹特斯之室
   this.setLastabardTime(time);
   break;
  }
}
/**
  * 是否在計時地圖 <br>
  * 
  * @return true:玩家位於限時的地圖內
  */
public boolean isInTimeMap() {
  final int map = this.getMapId();
  final int maxMapUsetime = MapsTable.getInstance().getMapTime(map);
  return maxMapUsetime > 0;
}

3.
MySqlCharacterStorage.java 關係到人物資料儲存
尋找
loadCharacter

增加

pc.setRocksPrisonTime(rs.getInt("RocksPrisonTime"));
pc.setIvoryTowerTime(rs.getInt("IvorytowerTime"));
pc.setLastabardTime(rs.getInt("LastabardTime"));

尋找

storeCharacter

SQL指令碼內增加

,RocksPrisonTime=?,IvorytowerTime=?,LastabardTime=?

執行動作增加

pstm.setInt(++i, pc.getRocksPrisonTime());
pstm.setInt(++i, pc.getIvoryTowerTime());
pstm.setInt(++i, pc.getLastabardTime());

characters.sql 增加RocksPrisonTime,IvorytowerTime,LastabardTime三個欄位

此文只分享於浪漫物語網路社區,轉載請著名作者,出處


4.
寫一個執行緒來增加或更新時間


import java.util.Calendar;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;
import l1j.server.config.Config_Server;
import l1j.server.server.datatables.MapsTable;
import l1j.server.server.model.L1Teleport;
import l1j.server.server.model.L1World;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.identity.L1SystemMessageId;
import l1j.server.server.serverpackets.S_MapTimer;
import l1j.server.server.serverpackets.S_ServerMessage;

/**
* 計時地圖執行緒

* @author Psnnwe

*/
public final class MapTimerThread extends Thread {

/**
  * 實例
  */
private static MapTimerThread _instance;

/**
  * 提示信息.
  */
private static final Logger LOG = Logger.getLogger(MapTimerThread.class
   .getName());

/**
  * 取回實例
  * 
  * @return
  */
public static MapTimerThread getInstance() {
  if (_instance == null) {
   _instance = new MapTimerThread();
   _instance.start();
  }
  return _instance;
}

/**
  * 日曆
  * 
  * @return
  */
private Calendar getRealTime() {
  final TimeZone tz = TimeZone.getTimeZone(Config_Server.TIME_ZONE);
  final Calendar cal = Calendar.getInstance(tz);
  return cal;
}

/**
  * 地圖時間檢查
  * 
  * @param pc
  */
private void MapTimeCheck(final L1PcInstance pc) {
  // 玩家所在的地圖
  final int map = pc.getMapId();
  // 地圖限制時間(秒數)
  final int maxMapUsetime = MapsTable.getInstance().getMapTime(map) * 60;
  final Calendar time = this.getRealTime();
  // 取回今年的第幾天
  int dayofyear = time.get(Calendar.DAY_OF_YEAR);
  if (dayofyear == 365) {
   dayofyear += 1;
  }
  // 使用秒數(取餘數)
  final int entertime = pc.getMapUseTime(map) % 100000;
  // 使用日期(取整數)
  final int enterday = pc.getMapUseTime(map) / 100000;
  if (entertime > (maxMapUsetime)) {
   this.teleport(pc);
  } else if (enterday < dayofyear) {
   // 不同天-更新日期
   pc.setMapUseTime(map, time.get(Calendar.DAY_OF_YEAR) * 100000);
  } else {
   this.message(pc);
   pc.setMapUseTime(map, pc.getMapUseTime(map) + 1);
   // 已使用時間(秒)
   final int usetime = pc.getMapUseTime(map) % 100000;
   // 剩餘時間(秒)
   final int can_useTime = (maxMapUsetime - usetime);
   if ((entertime % 60) == 0) {// 計時器顯示(1分鐘來一次就好了= = )
    pc.sendPackets(new S_MapTimer(can_useTime));
   }
  }
}

/**
  * 時間提示訊息
  * 
  * @param pc
  */
private void message(final L1PcInstance pc) {
  // 玩家所在的地圖
  final int map = pc.getMapId();
  // 地圖限制時間(秒數)
  final int maxMapUsetime = MapsTable.getInstance().getMapTime(map) * 60;
  // 取回地圖使用時間(秒) --- (取餘數(不取日期))
  final int time = pc.getMapUseTime(map) % 100000;
  final int usetime = maxMapUsetime - time; // 秒數
  S_ServerMessage msg = null;
  switch (usetime) {
  case 10800:
   msg = new S_ServerMessage(L1SystemMessageId.$1526,
     String.valueOf(3));
   break;
  case 7200:
   msg = new S_ServerMessage(L1SystemMessageId.$1526,
     String.valueOf(2));
   break;
  case 3600:
   msg = new S_ServerMessage(L1SystemMessageId.$1526,
     String.valueOf(1));
   break;
  case 1800:
   msg = new S_ServerMessage(L1SystemMessageId.$1527,
     String.valueOf(30));
   break;
  case 900:
   msg = new S_ServerMessage(L1SystemMessageId.$1527,
     String.valueOf(15));
   break;
  case 600:
   msg = new S_ServerMessage(L1SystemMessageId.$1527,
     String.valueOf(10));
   break;
  case 300:
   msg = new S_ServerMessage(L1SystemMessageId.$1527,
     String.valueOf(5));
   break;
  case 120:
   msg = new S_ServerMessage(L1SystemMessageId.$1527,
     String.valueOf(2));
   break;
  case 60:
   msg = new S_ServerMessage(L1SystemMessageId.$1527,
     String.valueOf(1));
   break;
  case 10:
   msg = new S_ServerMessage(L1SystemMessageId.$1528,
     String.valueOf(10));
   break;
  case 9:
   msg = new S_ServerMessage(L1SystemMessageId.$1528,
     String.valueOf(9));
   break;
  case 8:
   msg = new S_ServerMessage(L1SystemMessageId.$1528,
     String.valueOf(8));
   break;
  case 7:
   msg = new S_ServerMessage(L1SystemMessageId.$1528,
     String.valueOf(7));
   break;
  case 6:
   msg = new S_ServerMessage(L1SystemMessageId.$1528,
     String.valueOf(6));
   break;
  case 5:
   msg = new S_ServerMessage(L1SystemMessageId.$1528,
     String.valueOf(5));
   break;
  case 4:
   msg = new S_ServerMessage(L1SystemMessageId.$1528,
     String.valueOf(4));
   break;
  case 3:
   msg = new S_ServerMessage(L1SystemMessageId.$1528,
     String.valueOf(3));
   break;
  case 2:
   msg = new S_ServerMessage(L1SystemMessageId.$1528,
     String.valueOf(2));
   break;
  case 1:
   msg = new S_ServerMessage(L1SystemMessageId.$1528,
     String.valueOf(1));
   break;
  default:
   break;
  }
  pc.sendPackets(msg);
}

@Override
public void run() {
  System.out.println("╠》載入 - 計時地圖執行緒。");
  while (true) {
   try {
    for (final L1PcInstance pc : L1World.getInstance()
      .getAllPlayers()) {
     if ((pc == null) || (pc.getNetConnection() == null)) {
      continue;
     } else {
      if (pc.isDead()) {// 死亡不計時
       continue;
      } else {
       if (pc.isInTimeMap()) {// 離開地圖不計時
        this.MapTimeCheck(pc);
       }
      }
     }
    }
    final int time = 1 * 1000;
    Thread.sleep(time);// 1秒一次
   } catch (final Throwable e) {
    LOG.log(Level.WARNING, e.getLocalizedMessage(), e);
   }
  }
}

/**
  * 傳送處理.(這邊只舉例奇岩地監)
  * 
  * @param pc
  */
private void teleport(final L1PcInstance pc) {
  final int map = pc.getMapId();
  if ((map == 53) || (map == 54) || (map == 55) || (map == 56)) {
   final int locx = 33427;
   final int locy = 32822;
   final int mapid = 4;
   final int heading = 5;
   L1Teleport.teleport(pc, locx, locy, mapid, heading, true);
  }
}
}

5.
GameServer.java 讓MapTimerThread伴隨伺服器啟動
尋找
initialize

方法內找地方增加

MapTimerThread.getInstance();

6.
封包的處理(ctrl+q)


import l1j.server.server.model.Instance.L1PcInstance;
/**
* 地圖剩餘時間(ctrl+q)

* @author Psnnwe

*/
public class S_MapTimerOutextends ServerBasePacket {
private byte[] _byte = null;
private static final String S_MAP_TIMER_OUT = "[S] S_MapTimerOut";
/**
  * ctrl+Q中地圖剩餘時間
  */
public static final int DISPLAY_MAP_TIME = 159;
/**
  * ctrl+Q顯示剩餘時間
  * 
  * @param pc
  */
public S_MapTimerOut(final L1PcInstance pc) {
  this.writeC(Opcodes_Server.S_OPCODE_PACKETBOX);
  this.writeC(DISPLAY_MAP_TIME);
  this.writeD(3);// 組數
  this.writeD(1);// 排序
  this.writeS("$12125"); // 奇岩監獄
  final int g_time = pc.getRocksPrisonTime() % 100000;
  final int g_maxTime = 10800; // 3小時(秒)
  final int g_newTime = g_maxTime - g_time;
  this.writeD(g_newTime);
  this.writeD(2);
  this.writeS("$6081"); // 象牙塔
  final int i_time = pc.getIvoryTowerTime() % 100000;
  final int i_maxTime = 3600; // 1小時(秒)
  final int i_newTime = i_maxTime - i_time;
  this.writeD(i_newTime);
  this.writeD(3);
  this.writeS("$12126"); // 拉斯塔巴德地監
  final int l_time = pc.getLastabardTime() % 100000;
  final int l_maxTime = 43200; // 12小時(秒)
  final int l_newTime = l_maxTime - l_time;
  this.writeD(l_newTime);
}
@Override
public byte[] getContent() {
  if (this._byte == null) {
   this._byte = this.getBytes();
  }
  return this._byte;
}
@Override
public String getType() {
  return S_MAP_TIMER_OUT;
}
}

7.
畫面左上角計時器


/**
* 計時地圖左上角計時器

* @author Psnnwe

*/
public final class S_MapTimer extends ServerBasePacket {
private static final String S_MAP_TIMER = "[S] S_MapTimer";
/**
  * 位元組
  */
private byte[] _byte;
/**
  * 顯示定時器地圖的剩餘時間
  **/
public static final int MAP_TIMER = 153;
/**
  * 地圖計時器
  * 
  * @param value
  *            剩餘的時間(秒)
  */
public S_MapTimer(final int value) {
  this.writeC(Opcodes_Server.S_OPCODE_PACKETBOX);
  this.writeC(MAP_TIMER);
  this.writeH(value);
}
@Override
public byte[] getContent() {
  if (this._byte == null) {
   this._byte = this.getBytes();
  }
  return this._byte;
}
@Override
public String getType() {
  return S_MAP_TIMER;
}
}

8.
C_NPCAction.java  NPC傳送
寫法不同請自行變通,在此只舉例奇岩  (注意是否再   if (obj instanceof L1NpcInstance)   判斷內)


case 自行輸入:
if (s.equalsIgnoreCase("teleportURL")) {
  pc.sendPackets(new S_NPCTalkReturn(npc.getId(),"merlin2"));
}
if (s.equalsIgnoreCase("teleport giranD")) { // 傳送至奇岩地監
  final Calendar time = this.getRealTime();
  final int entertime = pc.getRocksPrisonTime() % 100000;
  final int enterday = pc.getRocksPrisonTime() / 100000;
  final int dayofyear = time.get(Calendar.DAY_OF_YEAR);
  final int maxtime = 3 * 60 * 60;// 最多可停留的時間10800(秒)
  final int onehour = 1 * 60 * 60;// 1小時(3600秒)
  if ((entertime >= maxtime) && (enterday == dayofyear)) {
   pc.sendPackets(new S_ServerMessage(
     L1SystemMessageId.$1522, "3"));
   htmlid = "";
   return;
  } else {
   if (enterday < dayofyear) {
    pc.setRocksPrisonTime(dayofyear * 100000);
   }
   if (pc.getInventory().consumeItem(L1ItemId.ADENA,
     1000)) { // 檢查身上金幣是否足夠
    final int a = entertime % 60;
    if (a == 0) {
     final int b = (maxtime - entertime)
       / onehour; // 取回小時
     pc.sendPackets(new S_ServerMessage(
       L1SystemMessageId.$1526, "" + b
         + ""));
    } else if ((maxtime - entertime) < onehour) { // 不到一小時
     final int c = maxtime - entertime;
     pc.sendPackets(new S_ServerMessage(
       L1SystemMessageId.$1527, "" + c
         + ""));
    }
    L1Teleport.teleport(pc, 32806, 32735,
      (short) 53, 5, true);
   } else {
    PacketCreate.getInstance().sendSinglePackets(
      pc, L1SystemMessageId.$189);
    return;
   }
  }
}
break;

9.
C_Rank.java 查詢的部分
增加

case 8: // 查詢指令(/入場時間)
   // 取餘數(時間)
   final int g_entertime = pc.getRocksPrisonTime() % 100000;
   final int g_maxTime = 10800; // 3小時
   int g_newTime = (g_maxTime - g_entertime) / 60;
   if (g_newTime <= 0) {
    g_newTime = 0;
   }
   final S_ServerMessage rocksPrison = new S_ServerMessage(
     L1SystemMessageId.$2535, "$12125",
     String.valueOf(g_newTime)); // [奇岩監獄]
   pc.sendPackets(rocksPrison); // %0 : %0 : 剩餘時間 %1 分
   // 取餘數(時間)
   final int i_entertime = pc.getIvoryTowerTime() % 100000;
   final int i_maxTime = 3600; // 1小時
   int i_newTime = (i_maxTime - i_entertime) / 60;
   if (i_newTime <= 0) {
    i_newTime = 0;
   }
   final S_ServerMessage ivorytower = new S_ServerMessage(
     L1SystemMessageId.$2535, "$6081", String.valueOf(i_newTime)); // [象牙塔]
   pc.sendPackets(ivorytower); // %0 : %0 : 剩餘時間 %1 分
   // 取餘數(時間)
   final int l_entertime = pc.getLastabardTime() % 100000;
   final int l_maxTime = 43200; // 12小時
   int l_newTime = (l_maxTime - l_entertime) / 60;
   if (l_newTime <= 0) {
    l_newTime = 0;
   }
   final S_ServerMessage lastabard = new S_ServerMessage(
     L1SystemMessageId.$2535, "$12126",
     String.valueOf(l_newTime)); // [拉斯塔巴德地監]
   pc.sendPackets(lastabard); // %0 : %0 : 剩餘時間 %1 分
   break;
  case 9: // 地圖剩餘使用時間
   pc.sendPackets(new S_MapTimerOut(pc));
   break;
end

10.
C_SendLocation.java 發送座標位置(更新ctrl+q的顯示)
增加

case 9: // 更新Ctrl+Q的顯示時間
   pc.sendPackets(new S_MapTimerOut(pc));
   break;

沒有留言:

張貼留言