예전에 비슷한걸 만들었었는데..
팩이 변화..랄거까진 없고..
그냥 지나가다가 보여서 보강해둡니다.
============
빨간색 = 수정
파란색 = 검색
검은색 = 원본
초록색 = 주석
보라색 = 파일이름
============
L1Quest.java
// 로그아웃한 pc의 퀘스트 완료상태를 검색
public static boolean isEndLogoutPc(int pcid, int quest_id){
Connection con = null;
PreparedStatement pstm = null;
ResultSet rs = null;
int endCode = 0;
try{
con = L1DatabaseFactory.getInstance().getConnection();
pstm = con.prepareStatement("SELECT * FROM character_quests WHERE char_id=? and quest_id=?");
pstm.setInt(1, pcid);
pstm.setInt(2, quest_id);
rs = pstm.executeQuery();
while(rs.next()){
endCode = rs.getInt("quest_step");
}
}catch(SQLException e){
_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
}finally{
SQLUtil.close(rs);
SQLUtil.close(pstm);
SQLUtil.close(con);
}
if(endCode == 255){
return true;
}
return false;
}
===============================================================
C_ItemUse.java
...
} else if (itemId == 0000) { // 동일 계정 내 혈맹 가입 주문서(0000: 아이템번호)
if(pc.isCrown()){ // 군주라면
int messageCode = 87 + pc.get_sex();// 0: 남자, 1: 여자, 87:당신은 왕자입니다, 88: 당신은 공주입니다.
pc.sendPackets(new S_ServerMessage(messageCode));
return;
}
if(pc.getClanid() != 0){ // 혈맹이 있다면
pc.sendPackets(new S_ServerMessage(89)); // 이미 혈맹이 있습니다
return;
}
pc.getInventory().removeItem(l1iteminstance, 1); // 주문서 삭제
Connection con = null;
PreparedStatement pstm = null;
ResultSet rs = null;
int crownCount = 0; // 군주의 갯수를 세기 위한 임시변수
try {
con = L1DatabaseFactory.getInstance().getConnection();
// 쿼리는 필요정보로만 받아온다(동일계정상 군주인경우)
pstm = con.prepareStatement("SELECT * FROM `characters` WHERE account_name = "+pc.getAccountName()+" and Type = 0");
rs = pstm.executeQuery();
// 군주가 한명도 없다면
if(!rs.next()){
pc.sendPackets(new S_SystemMessage("당신의 계정에는 군주가 존재하지 않습니다."));
return;
}
// 군주가 있다면 맨 마지막 행으로 이동
rs.last();
// 행의 숫자를 받아온다.
crownCount = rs.getRow();
// 쿼리를 처음으로 복구
rs.first();
/*last()와 first()는 별로 추천되는 방법이 아니다.
쿼리가 많은경우 사소한 렉이라도 유발할수 있기 때문이다.
하지만 계정의 케릭터같은경우 정보를 보존하지 않는 일반 공개팩은 많아야 8개~10개수준이므로 이 방법을 사용한다.*/
// 군주의 숫자를 받아오지 못했다면
if(crownCount <= 0){
pc.sendPackets(new S_SystemMessage("군주를 받아오지 못했습니다."));
return;
}
// 군주가 1명 이상이라면
while(rs.next()){
// 혈맹id를 저장한다.
int crownClanid = rs.getInt("ClanID");
// 혈맹이 없다면 다른 군주를 받아온다
if(crownClanid == 0){
continue;
}
// 혈맹이 있다면 가입루틴 진행
int crownPcid = rs.getInt("objid"); // pcid
int crownPcLevel = rs.getInt("level"); // Level
String crownPcName = rs.getString("char_name"); // Name
String crownClanname = rs.getString("Clanname");// Clanname
int charisma = rs.getInt("Cha"); // Charisma
// 가입루틴을 진행
JoinClan(pc, crownPcid, crownPcLevel, crownPcName, crownClanid, crownClanname, charisma);
break;
}
} catch (Exception e) {
e.printStackTrace();
}finally{
SQLUtil.close(rs);
SQLUtil.close(pstm);
SQLUtil.close(con);
}
....
// 클랜 가입 루틴 처리
private void JoinClan(L1PcInstance joinPc, int crownPcid, int crownPcLevel, String crownPcName, int clan_id, String clanName, int charisma){
L1Clan clan = L1World.getInstance().getClan(clanName);
if(clan != null){
int maxMember = 0;
boolean lv45quest = false;
// 45레벨 퀘스트를 완료했다면
if(L1Quest.isEndLogoutPc(crownPcid, L1Quest.QUEST_LEVEL45)){
lv45quest = true;
}
if(crownPcLevel >= 50){ // Lv50 이상
if(lv45quest == true){ // Lv45 퀘스트 클리어가 끝난 상태
maxMember = charisma * 9;
}else{
maxMember = charisma * 3;
}
}else{ // Lv50 미만
if(lv45quest == true){// Lv45 퀘스트 클리어가 끝난 상태
maxMember = charisma * 6;
}else{
maxMember = charisma * 2;
}
}
if(Config.MAX_CLAN_MEMBER > 0){ // Clan 인원수의 상한의 설정 있어
maxMember = Config.MAX_CLAN_MEMBER;
}
if(joinPc.getClanid() == 0){ // 크란미가입
String clanMembersName[] = clan.getAllMembers();
if(maxMember <= clanMembersName.length){ // 빈 곳이 없다
joinPc.sendPackets(new S_ServerMessage(188, crownPcName)); // %0는 당신을 혈맹원으로서 받아들일 수가 없습니다.
return;
}
for(L1PcInstance clanMembers : clan.getOnlineClanMember()){
clanMembers.sendPackets(new S_ServerMessage(94, joinPc.getName())); // \f1%0이 혈맹의 일원으로서 받아들여졌습니다.
}
joinPc.setClanid(clan_id);
joinPc.setClanname(clanName);
joinPc.setClanRank(L1Clan.CLAN_RANK_PUBLIC);
try {
joinPc.save(); // DB에 캐릭터 정보를 기입한다
} catch (Exception e) {
e.printStackTrace();
}
clan.addMemberName(joinPc.getName());
joinPc.sendPackets(new S_ServerMessage(95, clanName)); // \f1%0 혈맹에 가입했습니다.
}else{ // 크란 가입이 끝난 상태
joinPc.sendPackets(new S_ServerMessage(89)); // \f1당신은 벌써 혈맹에 가입하고 있습니다.
}
}
}
====================================================================================
주의
1. 팩 별로 sql 쿼리의 구문이 다를 수 있습니다.
2. 팩 별로 sql 테이블, 필드명이 다를 수 있습니다.
3. 팩 별로 아이템 번호가 다를 수 있습니다.
그럼
ごきげんよう~
안녕하세요
가니입니다.
2009년 08월 20일자 옵코드 를 공개합니다.
옵코드 공개에 대한 문의는 받지 않습니다.
적용은 알아서들 해주시기 바랍니다.
1. ClientThread.java 를 수정합니다.
2. S_ServerVersion.java 를 수정합니다.
3. 첨부한 Opcodes.java, S_Unknown1.java, S_Unknown2.java 를 자신의 팩에 맞게 수정합니다.
4. 첨부한 접속도움파일로 접속을 합니다.
첨부파일
[1차 수정] Opcodes.java 파일의 오류를 수정
[2차 수정] S_Unknown2.java 의 사용법을 기술
Opcode_and_Connect.zip
--------------------
빨간색 = 추가
파란색 = 검색
검은색 = 원본
보라색 = 파일이름
초록색 = 주석&코멘트
====================================================================
ClientThread.java
private static final byte[] FIRST_PACKET = { // 2009.08.20
(byte) 0x12,
(byte) 0x00, // size
(byte) 0x49, // id
(byte) 0x0B, (byte) 0xEA, (byte) 0x7D,
(byte) 0x76, // key
(byte) 0xFD, (byte) 0xF4, (byte) 0xF8, (byte) 0x71, (byte) 0xA4, (byte) 0x17, (byte) 0xA4, (byte) 0x47, (byte) 0xE0,
(byte) 0x46, (byte) 0x54 };
...
long seed =0x767dea0bL;// 2009.08.20
==========================================================================
S_ServerVersion.java
public S_ServerVersion(){
int time = L1GameTimeClock.getInstance().getGameTime().getSeconds();
time = time - (time % 300);
writeC(Opcodes.S_OPCODE_SERVERVERSION);
writeC(0x00); // must be
writeC(0x14); // low version // Episode U
writeD(0x000162bd); // serverver
writeD(0x000162b4); // cache version
writeD(0x00016068); // auth ver
writeD(0x00016260); // npc ver
writeD(time); // 로그인시의 시간 설정
writeC(0x00); // unk 1
writeC(0x00); // unk 2
writeC(0x00); // 0:영어 8:일본어 // Episode U
}
=======================================================================
S_Unknown1.java
파일로 첨부
=====================================================================
S_Unknown2.java
파일로 첨부
=====================================================================
Opcodes.java
파일로 첨부
=======================================================================
C_CommonClick.java
client.sendPacket(new S_Unknown2(0));
client.sendPacket(new S_CharAmount(amountOfChars));
=======================================================================
C_LoginToServer.java
pc.sendPackets(new S_Unknown2(3)); // 주석 해제, 월맵 진입, 언노처리,
bookmarks(pc);
========================================================================
C_NewCharSelect.java
client.CharReStart(true);
client.sendPacket(new S_Unknown2(2)); // 리스버튼을 위한 구조변경 // Episode U
빼먹은게 있는지 모르겠군요.
해당 옵코드로 변경을 하시고 첨부한 파일로 접속을 하시면 08월 20일자 패치(아인하사드, 랜마)까지는 이용 가능하십니다.
그럼 다들 잘 적용하시기 바랍니다.
ps. 혹시 퍼가시는분들이 있으시다면 링크를 가져가세요.
글 자체를 복사해가시는 분이 있으시면 ''
이걸로 끝입니당~
by 가니
안녕하세요
가니입니다.
2009년 4월 29일자 옵코드를 적용하신 분들중 악세서리 강도를 추가 안하신 분들은,
방어구 옵션이 엉망으로 나올겁니다.
해당 부분을 수정하는 방법입니다.
바로 악세서리 강도를 추가 하는 방법인데요.
잘 따라하시면 됩니다.
1. armor.sql 테이블에 악세서리강도를 쓸 필드를 추가합니다.
2. 테이블에 값을 입력 후, 소스에서 필드값을 받아옵니다.
3. 아이템 정보를 보낼때 필드값도 보내도록 추가합니다.
--------------------
빨간색 = 추가
파란색 = 검색
검은색 = 원본
보라색 = 파일이름
초록색 = 주석&코멘트
====================================================================
armor.sql
테이블 설계하기 - 맨 마지막에 한줄 추가
이름 타입 길이 십진법 제로허용 기본값
solidity int 2 0 체크안함 255
====================================================================
armor.sql
추가한 필드에 값 입력
일반 방어구를 제외한 악세서리는 상, 중, 하 에 따라 값을 입력하셔야 합니다.
상 = 0
중= 1
하 = 2
ex)
제브레퀴의 마안(중) = 1
상중하 값은 리니지 홈페이지 파워북(악세서리) 를 보시면 있습니다.
=====================================================================
L1Item.java
//맨 아래에 추가
private int Solidity; // 아이템 강도
public int getSolidity(){
return Solidity;
}
public void setSolidity(int i){
Solidity = i;
}
======================================================================
ItemTable.java
private Map<Integer, L1Armor> allArmor(){
...
armor.setSolidity(rs.getInt("solidity"));
result.put(new Integer(armor.getItemId()), armor); // 검색후 윗줄 추가
======================================================================
L1ItemInstance.java
public byte[] getStatusBytes(){
...
}else if(itemType2 == 2){ // armor
// AC
os.writeC(19);
int ac = ((L1Armor) getItem()).get_ac();
if(ac < 0){
ac = ac - ac - ac;
}
os.writeC(ac);
os.writeC(getItem().getMaterial());
os.writeC(getItem().getSolidity()); // 아이템 강도를 표시, 악세제외 255(표시안함), 악세는 0(상), 1(중), 2(하)
os.writeD(getWeight());
}
=====================================================================================
이렇게 추가하시면 옵션표시가 잘 되실겁니다.
자신의 팩과 다른 부분은 수정을 해서 사용하시면 됩니다
그럼 다들 잘 되시길 바라겠습니다
ps. 혹시 퍼가시려면 링크만 가져가시기 바랍니다.
by 린프리덤 - 가니 && 라르후