Metin2 Questlerinizde Define Kullanın! (Qc ile)

Whistle

Ruhsuz :/
Kurucu
Geliştirici
Yardımsever Üye
Mesaj
11.919
Çözümler
564
Beğeni
13.411
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):
Genişlet Daralt Kopyala
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++:
Genişlet Daralt Kopyala
enum parse_state

En başa ekle:
C++:
Genişlet Daralt Kopyala
ST_DEFINE,

Ara:
C++:
Genişlet Daralt Kopyala
ostream & operator << (ostream & ostr, const Token& tok)

Kod blogunun altına şunları ekle:
C++:
Genişlet Daralt Kopyala
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++:
Genişlet Daralt Kopyala
void load_quest_function_list(const char* filename)

Kod blogunun altına ekle:
C++:
Genişlet Daralt Kopyala
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++:
Genişlet Daralt Kopyala
map<string, map<string, vector<AScript> > > state_arg_script_map;

Altına ekle:
C++:
Genişlet Daralt Kopyala
Constant constant;

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

Altına ekle:
C++:
Genişlet Daralt Kopyala
string lastDefine = "";

void parse(char * filename) kod blogunda ara:
C++:
Genişlet Daralt Kopyala
int nested = 0;

Altına ekle:
C++:
Genişlet Daralt Kopyala
string traFunc = "translating";

void parse(char * filename) kod blogunda ara:
C++:
Genişlet Daralt Kopyala
switch(ps)
        {
            case ST_START:

swtich(ps) kod blogunun içine en başa bunu ekle:
C++:
Genişlet Daralt Kopyala
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++:
Genişlet Daralt Kopyala
case ST_WHEN_NAME:

Bunu:
JavaScript:
Genişlet Daralt Kopyala
                        else
                        {
                            current_when_name = getstr(t.seminfo.ts);
lookahead(&lexstate);
                        }

Şu şekilde değiştir:
C++:
Genişlet Daralt Kopyala
                        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++:
Genişlet Daralt Kopyala
                        if (!current_when_argument.empty())
                        {
                            cout << " (";
                            cout << current_when_argument.substr(1);
                            cout << ")";
                        }

Şu şekilde değiştir:
C++:
Genişlet Daralt Kopyala
                        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++:
Genişlet Daralt Kopyala
case ST_WHEN_BODY:

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

Şu şekilde değiştir:
C++:
Genişlet Daralt Kopyala
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++:
Genişlet Daralt Kopyala
case ST_FUNCTION_BODY:

Bunu:
C++:
Genişlet Daralt Kopyala
os << lexstate.t << ' ';

Şu şekilde değiştir:
C++:
Genişlet Daralt Kopyala
                         // 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:
Genişlet Daralt Kopyala
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:
Üst