среда, 21 ноября 2012 г.

Тутор по установке соотношения цен при торговле

Думаю, нет надобности объяснять актуальность данной проблемы. В теме по скриптингу уже обсуждалось возможность динамического управления соотношением цен с помощью пакета Ikarus, написанного Sektenspinner-ом, однако была небольшая проблема - из-за специфики работы с памятью функций пакета, компиляция готиксорсером была невозможна, что усложняло реализацию для ленивых скриптеров вроде меня. Вчера лазя по польскому форуму themodders.org я наткнулся на упоминание первой версии Икаруса переделанной под Г1 orcwarrior-ом, и, о чудо, в отличие от последних версий там используются функции работы с памятью, не оптимизированные под движок с полным пренебрежением правил языка и готиксорсер работает с ними отлично. Сам пакет можно найти на немецком воге, но для данной цели нам надо только класс двига игры oCNpc (код его приводить не буду) и несколько функций, а именно: чтение и запись из памяти/в память из Икаруса и установка множителей для цен, написанная orcwarrior-ом.
Код:
const int MEM_NpcID_Offset   = 256; //0x100

const int MEMINT_oCInformationManager_Address = 10328072;//0x9D9808

//TODO: To everyone, in G1 there isn't universal hided wp like "TOT" in G2

//So You need to add some WP to all your worlds in hidden place and call them

//the same

const string MEM_FARFARAWAY = "GAME_START";

const string MEM_HELPER_NAME = "MEMHLP";

INSTANCE MEM_HELPER_INST (C_NPC)

{

    name = MEM_HELPER_NAME;

    id = 42;

    flags = NPC_FLAG_IMMORTAL;

    attribute   [ATR_HITPOINTS_MAX] = 2;

    attribute   [ATR_HITPOINTS]     = 2;

    Mdl_SetVisual           (self,  "meatbug.mds");

};

//######################################################

//

//  Elementare Read-Write Operationen

//

//######################################################

var oCNpc MEM_Helper;

var C_NPC MEM_oldOth; //other hier zwischenspeichern

func void MEMINT_GetMemHelper() {

    MEM_Helper = Hlp_GetNpc (MEM_HELPER_INST);

     if (!Hlp_IsValidNpc (MEM_Helper)) 

    {

        //self zwischenspeichern

        MEM_oldOth = Hlp_GetNpc (self);

        Wld_InsertNpc (MEM_HELPER_INST, MEM_FARFARAWAY);

        MEM_Helper = Hlp_GetNpc (self);

        self = Hlp_GetNpc (MEM_oldOth);

    };

};

var int MEMINT_OpenCount;

func void MEMINT_ReadOpen() 

{

    if (!MEMINT_OpenCount) 

    {

        MEMINT_GetMemHelper();

        MEM_oldOth = Hlp_GetNpc (other);

    };

    MEMINT_OpenCount += 1;

};

func void MEMINT_ReadClose() 

{

    MEMINT_OpenCount -= 1;

    if (!MEMINT_OpenCount) {

        MEM_Helper.enemy = 0;

        other = Hlp_GetNpc (MEM_oldOth);

    };

};

//Requires: Open, Close

func int MEMINT_ReadInt (var int address) {

    // other = address - MEM_NpcID_Offset 

    MEM_Helper.enemy = address - MEM_NpcID_Offset;

    // res wird nicht gebraucht, mьllt aber sonst den Stack zu!

    var int res; res = Npc_GetTarget (MEM_Helper);

    // res = *(other + oCNpc_idx_offset) 

    return other.id;

};

//Requires: Open, Close

func void MEMINT_WriteInt (var int address, var int val) 

{

    // other = address - MEM_NpcID_Offset 

    MEM_Helper.enemy = address - MEM_NpcID_Offset;

    // res wird nicht gebraucht, mьllt aber sonst den Stack zu! 

    var int res; res = Npc_GetTarget (MEM_Helper);

    // (other + oCNpc_idx_offset) = val 

    other.id = val;

};

func int MEM_ReadInt (var int address) 

{

    var int res;

    MEMINT_ReadOpen();

    res = MEMINT_ReadInt (address);

    MEMINT_ReadClose();

    return res;

};

func void MEM_WriteInt (var int address, var int val) 

{

    MEMINT_ReadOpen();

    MEMINT_WriteInt (address, val);

    MEMINT_ReadClose();

};

//==================================================

// Trade_ChangeSellMultiplier

// ----

// - mul have to be zfloat value

// - function should be refreshed atleast every trade 

//   for simplify you can add it in ZS_TALK

//==================================================

func void Trade_ChangeSellMultiplier(var int mul)

{

        var int ptr;

        ptr = MEMINT_oCInformationManager_Address;

        ptr = MEM_ReadInt(ptr+24);//oCInformationManager.dlgTrade

        ptr = MEM_ReadInt(ptr+260);     //dlgTrade.oCViewDialogItemContainer

        MEM_WriteInt(ptr+268,mul);//oCViewDialogItemContainer.Multiplier = mul

};

//==================================================

// Trade_ChangeBuyMultiplier

// ----

// - mul have to be zfloat value

// - function should be refreshed atleast every trade 

//   for simplify you can add it in ZS_TALK

//==================================================

func void Trade_ChangeBuyMultiplier(var int mul)

{

        var int ptr;

        ptr = MEMINT_oCInformationManager_Address;

        ptr = MEM_ReadInt(ptr+24);//oCInformationManager.dlgTrade

        ptr = MEM_ReadInt(ptr+252);     //dlgTrade.oCViewDialogStealContainer

        MEM_WriteInt(ptr+268,mul);//oCViewDialogStealContainer.Multiplier = mul 

};
Можно просто вставить в проект уже готовый файл: OCNPC18M.rar (не забудьте вписать его в .src файл поближе к началу).
Что важно: специфика работы с памятью требует задачу переменных типа float в виде int. Благо, добрый orcwarrior описал процедуру языком, понятным даже чайникам вроде меня: переводим например здесь http://babbage.cs.qc.cuny.edu/IEEE-754/Decimal.html наш float в 32-х битное шестнадцатеричное, а его виндозным калькулятором в десятиричное представление (халява в общем).
Теперь можно приступить к использованию функций. Для примера то, что я тестировал: вставляем в функцию ZS_Talk:
Код:
 if (Npc_GetTrueGuild(self) == GIL_ORG || Npc_GetTrueGuild(self) == GIL_SLD || Npc_GetTrueGuild(self) == GIL_KDW)

    {

        if (Npc_GetTrueGuild(hero) == GIL_ORG)

        {

            Trade_ChangeBuyMultiplier (1069547520); // 1.5

            Trade_ChangeSellMultiplier (1050253721); // 0.3

        }

            else if (Npc_GetTrueGuild(hero) == GIL_SLD || Npc_GetTrueGuild(hero) == GIL_KDW)

            {

                Trade_ChangeBuyMultiplier (1065353216); // 1.0

                Trade_ChangeSellMultiplier (1053609164); // 0.4

            }

                else if (Npc_GetTrueGuild(hero) == GIL_STT || Npc_GetTrueGuild(hero) == GIL_GRD 

                    || Npc_GetTrueGuild(hero) == GIL_KDF)

                {

                    Trade_ChangeBuyMultiplier (1077936128); // 3.0

                    Trade_ChangeSellMultiplier (1041865113); // 0.15

                }

                    else

                    {

                        Trade_ChangeBuyMultiplier (1073741824); // 2.0

                        Trade_ChangeSellMultiplier (1045220556); // 0.2

                    };

    };

    if (Npc_GetTrueGuild(self) == GIL_NOV || Npc_GetTrueGuild(self) == GIL_TPL || Npc_GetTrueGuild(self) == GIL_GUR)

    {

        if (Npc_GetTrueGuild(hero) == GIL_NOV)

        {

            Trade_ChangeBuyMultiplier (1069547520); // 1.5

            Trade_ChangeSellMultiplier (1050253721); // 0.3

        }

            else if (Npc_GetTrueGuild(hero) == GIL_TPL || Npc_GetTrueGuild(hero) == GIL_GUR)

            {

                Trade_ChangeBuyMultiplier (1065353216); // 1.0

                Trade_ChangeSellMultiplier (1053609164); // 0.4

            }

                    else

                    {

                        Trade_ChangeBuyMultiplier (1073741824); // 2.0

                        Trade_ChangeSellMultiplier (1045220556); // 0.2

                    };

    };

    if (Npc_GetTrueGuild(self) == GIL_STT || Npc_GetTrueGuild(self) == GIL_GRD || Npc_GetTrueGuild(self) == GIL_KDF)

    {

        if (Npc_GetTrueGuild(hero) == GIL_STT)

        {

            Trade_ChangeBuyMultiplier (1069547520); // 1.5

            Trade_ChangeSellMultiplier (1050253721); // 0.3

        }

            else if (Npc_GetTrueGuild(hero) == GIL_GRD || Npc_GetTrueGuild(hero) == GIL_KDF)

            {

                Trade_ChangeBuyMultiplier (1065353216); // 1.0

                Trade_ChangeSellMultiplier (1053609164); // 0.4

            }

                else if (Npc_GetTrueGuild(hero) == GIL_ORG || Npc_GetTrueGuild(hero) == GIL_SLD 

                     || Npc_GetTrueGuild(hero) == GIL_KDW)

                {

                    Trade_ChangeBuyMultiplier (1077936128); // 3.0

                    Trade_ChangeSellMultiplier (1041865113); // 0.15

                }

                    else

                    {

                        Trade_ChangeBuyMultiplier (1073741824); // 2.0

                        Trade_ChangeSellMultiplier (1045220556); // 0.2

                    };

    };
На выходе получаем: торговцы своего лагеря при принятии в призраки/воры/послушники будут свои товары отдавать в полтора раза дороже, а принимать за 30% стоимости. При последующем продвижении - продавать по реальной цене, а скупать за 40%. Для не самых дружественных Старого и Нового, при принадлежности к противоположному лагерю цена продажи вырастет до 3-х, а покупки упадет до 15%. В остальных случаях покупка за удвоенную цену, а продажа за 20%. Важно не забыть следующее: при коэффициенте покупки менее 50% руда будет приниматься торговцами за 0, так что желательно ее удорожить или использовать другое соотношение цен.

Автор: George_M
09.08.2011

0 коммент.:

Отправить комментарий

Open Panel

Blogroll

Вверх

Вниз