Metin2 Questlerinizde Define Kullanın! (Qc ile)

Whistle

S İ N İ R L E N M E K
Site yetkilisi
Kurucu
Kurumsal Üye
Geliştirici
Yardımsever Üye
Mesaj
11.567
Çözümler
551
Beğeni
12.247
Puan
5.915
Ticaret Puanı
2
Merhaba arkadaşlar,
Casro2 serverini geliştirirken güzel bir şey keşfettim ve sizle paylaşmak istiyorum.
Metin2'nin ana görevlerini çevirirken ilginç bir tabir gördüm. Questlerin başında define ibaresi yazıyordu.
Haliyle o questleri build etmeye çalışınca hata alıyordum. Bu hatanın sebebi qc dosyamızda define ibaresinin ekli olmaması. Vanilla'nın srcsinde bunun ekli olduğunu gördüm ve kendi srcmin qc dosyasına da eklemeye çalıştım ve başarılı oldum.
Her şeyden önce...

Define nedir?
Define bir şeyleri tanımlamak için kullanılıyor. Biz burada sabit bir değişken olarak kullanacağız.
Örnek kullanım;
Lua (Quest):
define kesilecekMob 171
define kesilecekMobAdet 10

quest partyKillTest begin
    state start begin
        when login or levelup begin
            set_state(gorev1)
        end
    end

    state gorev1 begin
        when kesilecekMob.party_kill with pc.getqf("partykilltestDurum") == 1 begin
            local sayim = pc.getqf("partykilltestSayim") - 1
            if sayim <= kesilecekMobAdet then
                pc.setqf("partykilltestSayim", sayim)
                q.set_counter("Aç Yabani Köpek", sayim)
            end
 
            if sayim == 0 then
                pc.setqf("partykilltestDurum", 0)
                pc.setqf("partykilltestSayim", 0)
                clear_letter()
            end
        end
    end
 
    state __COMPLETE__ begin
    end

end

Bu kodu ben bir şeyi test etmek için yazmıştım. Fakat kodun bir çok bölümünü sildim. Burada önemli olan defineleri nerede kullanabileceğimiz.
Örnektede gördüğünüz için sayıları sürekli aklınızda tutmak yerine. Defineler tanımlayarak çook uzun questlerinizde rahatlıkla kullanabilirsiniz.
İleride questte değişiklik yaparken mesela kesme sayısını 10 değilde 20 yapacağız. Normalde her yerde bulup değiştirmek gerekiyor. Fakat burada definenin değerini değiştirince her yerde değişmiş olacak. Ne kaaa pratik dimi ^_^

qc dosyamıza nasıl ekleriz?
Çalışacağımız dosya;
game/src/quest/gc.cc dosyasıdır. Bu dosyayı açıp aşağıdaki işlemleri sırasıyla tamamlayın;
Not: Novaline srcsinin qc dosyasında yapılmıştır!!

Ara:
C++:
enum parse_state

En başa ekle:
C++:
ST_DEFINE,

Ara:
C++:
ostream & operator << (ostream & ostr, const Token& tok)

Kod blogunun altına şunları ekle:
C++:
string token2string(const Token& t)
{
    stringstream ss;
    string token;
    ss << t;
    getline(ss, token);
    return token;
}

static bool testnext(LexState * ls, std::string str) {
    if (token2string(ls->t) == str) {
        next(ls);
        return true;
    } else
        return false;
}

Ara:
C++:
void load_quest_function_list(const char* filename)

Kod blogunun altına ekle:
C++:
class Constant {
    map<string, string> storage;
public:
    Constant() {}
 
    void create(std::string key, std::string value) {
        storage[key] = value;
    }
 
    void create(std::string key, const Token& t) {
        string tvalue = token2string(t);

        if (t.token == TK_STRING) {
            tvalue.erase(0, 1);
            tvalue.erase(tvalue.size() - 1, tvalue.size());
            storage[key] = tvalue;
        } else if (t.token == TK_NUMBER) {        
            storage[key] = token2string(t);
        } else if (t.token == TK_NAME) {
            storage[key] = storage[tvalue];
        } else {
            error("Gecersiz define formatı. define CONSTANT \"deger\"");
        }
    }

    std::string get(std::string key) {
        return storage[key];
    }
 
    bool exists(std::string key) {
        return ! (storage.find(key) == storage.end());
    }
};

void parse(char * filename) kod blogunda ara:
C++:
map<string, map<string, vector<AScript> > > state_arg_script_map;

Altına ekle:
C++:
Constant constant;

void parse(char * filename) kod blogunda ara:
C++:
Token& t= lexstate.t;

Altına ekle:
C++:
string lastDefine = "";

void parse(char * filename) kod blogunda ara:
C++:
int nested = 0;

Altına ekle:
C++:
string traFunc = "translating";

void parse(char * filename) kod blogunda ara:
C++:
switch(ps)
        {
            case ST_START:

swtich(ps) kod blogunun içine en başa bunu ekle:
C++:
case ST_DEFINE:
            {
                if (t.token == TK_QUEST) {
                    ps = ST_QUEST;
                    continue;
                }
 
                if (t.token == TK_NAME && string("define").compare(token2string(lexstate.t)) == 0) {
                    next(&lexstate);

                    if (lexstate.t.token == TK_NAME) {
                        lastDefine = token2string(lexstate.t);
                    } else {
                        error("Invalid constant name format.");
                    }
                    next(&lexstate);
    
                    constant.create(lastDefine, lexstate.t);
                }
            }
            break;


void parse(char * filename) kod blogunda ara:
C++:
case ST_WHEN_NAME:

Bunu:
JavaScript:
                        else
                        {
                            current_when_name = getstr(t.seminfo.ts);
lookahead(&lexstate);
                        }

Şu şekilde değiştir:
C++:
                        else
                        {
                            current_when_name = getstr(t.seminfo.ts);
                            if (constant.exists(current_when_name)) { //c2 define okuyucu
                                current_when_name = constant.get(current_when_name);
                            }
                            lookahead(&lexstate);
                        }

Bunu:
C++:
                        if (!current_when_argument.empty())
                        {
                            cout << " (";
                            cout << current_when_argument.substr(1);
                            cout << ")";
                        }

Şu şekilde değiştir:
C++:
                        if (!current_when_argument.empty())
                        {
                            if (constant.exists("_TRA_"))
                            {
                                traFunc = constant.get("_TRA_");
                            }
               
                            size_t fpos = current_when_argument.find(traFunc);

                            if (fpos != string::npos) {
                                fpos += traFunc.size();
                                if (fpos < current_when_argument.size() && current_when_argument[fpos] == '.') {
                                    current_when_argument[fpos] = '(';
                                    current_when_argument.append(")");
                                }  else {
                                    error("tra fonksiyonu yanlis kullanilmis.");
                                }
                            }
               
                            cout << " (";
                            cout << current_when_argument.substr(1);
                            cout << ")";
                        }

void parse(char * filename) kod blogunda ara:
C++:
case ST_WHEN_BODY:

Bunu:
C++:
                        if (nested==2) break;
                        os << lexstate.t << ' ';
                        prev = lexstate;
                        next(&lexstate);

Şu şekilde değiştir:
C++:
if (nested==2) break;
              
                         /* Replace vars or function names with our constant value */
          
                        string tmpStr = token2string(lexstate.t);
              
                        if (lexstate.t.token == TK_NAME)
                        {
                            string ckey = token2string(lexstate.t);
                  
                            if (constant.exists(ckey))
                            {
                                tmpStr = constant.get(ckey);
                            }
                        }
                        os << tmpStr << ' ';
              
                        //os << lexstate.t << ' ';
                        prev = lexstate;
                        next(&lexstate);

void parse(char * filename) kod blogunda ara:
C++:
case ST_FUNCTION_BODY:

Bunu:
C++:
os << lexstate.t << ' ';

Şu şekilde değiştir:
C++:
                         // Same piece of code used above - need refactoring
                        string tmpStr = token2string(lexstate.t);
                     
                        if (lexstate.t.token == TK_NAME)
                        {
                            string ckey = token2string(lexstate.t);
                         
                            if (constant.exists(ckey))
                            {
                                tmpStr = constant.get(ckey);
                            }
                        }
                        os << tmpStr << ' ';
                        //os << lexstate.t << ' ';

İşlemler bu kadardır.
Daha sonra build edebilirsiniz. qc dosyasını build etmek için;
Kod:
game/src/quest && gmake clean
gmake -j20

Build olduktan sonra qc dosyasını alıp game/share/locale/turkey/quest içine atın.

Bu eklediğimiz kodların çalışma mantığı şu şekildedir. Siz questinizi build ederken eğer define belirtmişseniz. Sistem bunu önbelleğe alıyor. Daha sonra bu defineleri nerelerde kullandıysanız onu definenin değeri ile değiştiriyor. Kısacası oyunun çekirdek dosyasında hiçbir değişiklik yapmanıza gerek yok. Bu düzenlemeler sadece questlerin yazımı daha kolay ve anlaşılabilir olması içindir.

Konunun tüm anlatımı bana aittir arkadaşlar. Ne yazık ki çok araştırdım ama bulamadım. Elimdeki vanilla src sağolsun ondan bu kodları çıkarttım...
 
Son düzenleme:
Geri
Üst