Portal-Zone Gothic-Zone Gothic II-Zone Gothic 3-Zone Gothic 4-Zone Modifikationen-Zone Download-Zone Foren-Zone RPG-Zone Almanach-Zone Spirit of Gothic

 

Seite 1 von 2 12 Letzte »
Ergebnis 1 bis 20 von 27
  1. Beiträge anzeigen #1 Zitieren
    Local Hero
    Registriert seit
    Feb 2017
    Beiträge
    270
     
    F a w k e s ist offline

    G1/G2 Simple dialogs font change and color change

    Hello folks,
    I've been working on a feature, that would allow anyone to simply change font and color of each and every dialog option. Easiest way possible which came to my mind was to handle this directly with dialog description itself.

    Here is an example on how to use it in dialogs:

    Code:
    INSTANCE DIA_TestDialog_Orange (C_Info) {
           description    = "f@font_15_white.tga fs@font_old_20_white.tga h@FF8000 hs@FFB266 Orange !";
    };
    Script will 'scan' dialog description for modifiers:
    "f@" fontname
    "fs@" fontname for selected option
    "h@" color
    "hs@" color for selected option
    "al@" align text left
    "ac@" align text center
    "ar@" align text right
    "a@" dialog will be enabled for answers (it will work as input field)
    "s@spinnerID" dialog will be enables as a spinner

    If any of these modifiers is found, script will extract font names + color hex codes and will apply them in dialog choice box.
    Dialog in this example will apply font f@ 'font_15_white.tga' and dark orange color h@ 'FF8000' for greyed out option + hs@ 'font_old_20_white.tga' and light orange color hs@ 'FFB266' for selected option:
    [Bild: GM-Dialog-Choice-01.png]

    How can this be useful?
    Well, visualisation is always useful
    In my mod I have implemented in G1 a different method of Pickpocketing - one that is triggered via dialog option.
    (https://forum.worldofplayers.de/foru...1#post26129042)
    With my new pickpocketing system there is no punishment for player - you can either steal 1 item from NPC if your dexterity > NPCs dexterity or you can't steal anything.
    If you don't have enough dexterity points - dialog option will be orange (and will tell you how much points you are missing).
    If you have enough dexterity points - option will be green:
    [Bild: GM-Dialog-Choice-02.png]

    Within DIA_PickPocket condition function DIA_PickPocket_Condition I am changing description and color as I want:
    (in this case I am not touching font type - only applying new colors to default font)
    Code:
    const string DIALOG_PICKPOCKET = "(pickpocketing)";
    
    INSTANCE DIA_PickPocket (C_Info) {
           nr             = 787;
           condition      = DIA_PickPocket_Condition;
    };
    
    FUNC INT DIA_PickPocket_Condition () {
           var string newDescription; newDescription = "";
    
           //Adjust description
           if (self.attribute [ATR_DEXTERITY] <= hero.attribute [ATR_DEXTERITY])
           {
                  //Cocatenate green color with DIALOG_PICKPOCKET string
                  newDescription = ConcatStrings ("h@00CC66 hs@66FFB2 ", DIALOG_PICKPOCKET);
           } else {
                  var int delta;
    
                  delta = self.attribute [ATR_DEXTERITY] - hero.attribute [ATR_DEXTERITY];
    
                  newDescription = ConcatStrings (DIALOG_PICKPOCKET, " ");
                  newDescription = ConcatStrings (newDescription, IntToString (delta));
    
                  //Cocatenate orange color with DIALOG_PICKPOCKET string
                  newDescription = ConcatStrings ("h@FF8000 hs@FFB266 ", newDescription);
           };
    
           DIA_PickPocket.description = newDescription;
           ...
    };
    Hook _HOOK_INFORMATIONMANAGER_UPDATE below is able to work with both dialog instances and dialog choices (those added via Info_ClearChoices + Info_AddChoice).

    I tested it with Gothic 1 using both LeGo 2.5.1 and Ikarus 1.2.2 (might be it will work properly with older versions as well)
    I am not sure about Gothic 2 compatibility - somebody will have to test it.

    Requirements:


    Couple of notes:
    I hooked oCInformationManager__Update to get dialog choices updated - but most likely there is a better address at which this hook function can be run (I am not using IDA, so I am quite limited!)

    edit:
    this is fixed now:
    (At the moment for a split second you can see dialogs in their full format - for example "f#font_15_white.tga fs#font_old_20_white.tga c#FF8000 cs#FFB266 Orange !".)
    edit2:
    I had to add back condition if (dlg.IsActivated == 1) - Gothic crashed occasionally without it. Also fixed calculation for STR_SubStr - which was raising:
    MEM_WARN('STR_SubStr: The end of the desired substring exceeds the end of the string.') + 21 bytes
    edit3:
    Function oCInfoManager_GetInfo replaced with oCInfoManager_GetInfoUnimportant - to skip important dialogs.
    edit4:
    New feature 'Answers' added - basically giving user input field, into which an answer can be written.
    edit5:
    New feature 'Spinner' added - allowing you increase/decrease value of global variable 'InfoManagerSpinnerValue'.
    edit6:
    Text alignment added + Answer and spinner indicators.

    The way the code is written - it is important to keep these modifiers in exact order as shown below - otherwise script will not work properly (you can omit any of them, but order should not change):
    "f@", "fs@", "h@", "hs@", "al@", "ac@", "ar@", "a@", "s@spinnerID".

    Modifiers have to be separated with space.

    Color code which I have demonstrated - example h@00CC66 is containing RGB translated to hex code. But actually you can use R G B A h@00CC6660 and therefore play around with transparency of the text:
    [Bild: GM-Dialog-Choice-03.png]

    Code:
    Code:
    //G1 standard dialog - white color FFFFFF
    const string InfoManagerDefaultDialogColorSelected = "FFFFFF";
    //G1 standard dialog - grey color C8C8C8
    const string InfoManagerDefaultColorDialogGrey = "C8C8C8";
    
    
    //0 - left, 1 - center, 2 - center
    const int InfoManagerDefaultDialogAlignment = 0;
    
    
    //Dialog 'Answers'
    var int InfoManagerAnswerPossible;
    var int InfoManagerAnswerMode;
    var string InfoManagerAnswer;
    
    
    //Dialog 'Spiners'
    var int InfoManagerSpinnerPossible;
    var int InfoManagerSpinnerValue;
    var string InfoManagerSpinnerID;
    
    
    var int InfoManagerSpinnerPageSize; //Page Up/Page Down
    var int InfoManagerSpinnerValueMin; //Home
    var int InfoManagerSpinnerValueMax; //End
    
    
    //Variables used for elimination of unnecessary code runs
    var int InfoManagerLastChoiceSelected;
    var int InfoManagerUpdateState;
           const int cIM2BChanged    = 0;
           const int cIMChanged    = 1;
    
    
    //No idea where I got these class definition from :( most likely from Lehona :)
    //(this was a dark era of me collecting different snippets of code and putting them to one ugly text file without any links to original source)
    class zCViewText2 {
           var int validcolor; // bool //0
           var int remove; // bool //4
           
           var int posx; // zCPosition //8
           var int posy; // zCPosition //12
           
           var int timer;      //zREAL //übrige Zeit für PrintScreen anzeigen die nur eine bestimmte Zeit dauern? //16
           var string text;    //zstring //Die Entscheidende Eigenschaft. //20
           var int alphaFunc; //24
           var int font;       //zCFont* //28
           var int color;      //zCOLOR //32
           var int alpha;      //zBOOL //36
           var int useAlpha;    //zBOOL //40
    };
    
    
    class zCViewDialogChoice {
           var int _vtbl;               //0
           var int refctr;              //4
           var int hashindex;          //8
           var int next;                //12
        
           /*
           Seems like at u16 there is actually a string! which was so far completely empty
           var int u16;                 //16            //zString_vtbl                    = 8193768;    
           var int u20;                 //20
           var int u24;                 //24
           var int u28;                 //28
           var int u32;                 //32
           */
           var string uString;
    
    
           var int _zCViewBase_vtbl; //36
    
    
           var int vposx;              //int //40
           var int vposy;              //int //44
           var int vsizex;             //int //48
           var int vsizey;             //int //52
    
    
           //Aber auch "echt" Pixelpositionen
           var int pposx;              //int //56
           var int pposy;              //int //60
           var int psizex;             //int //64
           var int psizey;             //int //68
       
           var int key; //72
           var int parent; //76
    
    
           // Childs
           //zList <zCView>            childs
                  var int childs_compare;        //(*Compare)(zCView *ele1,zCView *ele2) // 80
                  var int childs_count;          //int //84
                  var int childs_last;           //zCView* //88
                  var int childs_wurzel;         //zCView* //92
    
    
           //var int alphafunc;           //96
           var int backTex;            //zCTexture* //96
           var int color;                //100
           var int alpha;                //104
    
    
           //zVEC2 TexturePosition [2]; // probably UV coords on texture
           var int texPos_0[2]; // 108,112
           var int texPos_1[2]; // 116,120
    
    
           var int isOpen;    //zBOOL  //124
           var int isClosed;    //zBOOL //128
           // time elapse during open/close, better not modify
           var int timeOpen;    //zREAL //132
           var int timeClose;    //zREAL //136
           // duration open/close takes to finish
           var int durOpen;    //zREAL //140
           var int durClose;    //zREAL //144
    
    
           /*
           enum zTViewFX: {
                  VIEW_FX_NONE        = 0,
                  VIEW_FX_ZOOM        = 1,
                  VIEW_FX_FADE        = VIEW_FX_ZOOM << 1,
                  VIEW_FX_BOUNCE      = VIEW_FX_FADE << 1,
     
                  VIEW_FX_FORCE_DWORD = 0xffffffff
           }*/
           var int fxOpen;    //zTViewFX //148
           var int fxClose;    //zTViewFX //152
    
    
           //zVEC2       TextureOffset[2]; //  offset to be added to texture coordinates
           var int texOffset_0[2]; // 156,160
           var int texOffset_1[2]; // 164,168
    
    
           //typedef zCArray< zCViewText2* > zCListViewText;
           var int m_listLines_array;     //zstring*  //172
           var int m_listLines_numAlloc;  //int     //176
           var int m_listLines_numInArray;//int    //180
    
    
           /*enum zEViewAlignment
           {
                  VIEW_ALIGN_NONE     ,
                  VIEW_ALIGN_MAX      ,
                  VIEW_ALIGN_MIN      ,
                  VIEW_ALIGN_CENTER  
           }
           var int algin //zTViewAlign;*/
           /*
           enum zTRnd_AlphaBlendFunc   {   zRND_ALPHA_FUNC_MAT_DEFAULT,
                                    zRND_ALPHA_FUNC_NONE,          
                                    zRND_ALPHA_FUNC_BLEND,          
                                    zRND_ALPHA_FUNC_ADD,                    
                                    zRND_ALPHA_FUNC_SUB,                    
                                    zRND_ALPHA_FUNC_MUL,                    
                                    zRND_ALPHA_FUNC_MUL2,                  
                                    zRND_ALPHA_FUNC_TEST,          
                                    zRND_ALPHA_FUNC_BLEND_TEST      
           };  */
           var int alphaFunc; // 184
           var int font;              //188
           var int fontColor;                  //zCOLOR b, g, r, a //192
           var int fontAlpha;                  //int //196
    
    
           var int u200; //200
    
    
           var int cursorx; //204
           var int cursory; //208
    
    
           var int offsetTextpx; //212
           var int offsetTextpy; //216
    
    
           var int sizeMargin_0[2]; // 220,224
           var int sizeMargin_1[2]; // 228,232
    
    
           var int event; //236
           var int IsDone; //zBOOL //240
           var int IsActivated; //zBOOL //244
           var int ColorSelected; //zCOLOR //248
           var int ColorGrayed; //zCOLOR //252
           var int  ChoiceSelected; //256
           var int  Choices;   //260
           var int  LineStart; //264
           var int u268; //268
           var int u272; //272
           var int u276; //276
    };
    
    
    instance zCViewText2@ (zCViewText2);
    var int InfoManagerSpinnerIndicator;
    var int InfoManagerAnswerIndicator;
    
    
    /***
        Function will return specific instance of displayed dialog option
    ***/
    /*
    FUNC INT oCInfoManager_GetInfo (var int npcInstance, var int herInstance, var int index) //oCInfo *
    {
          //00664E50  .text     Debug data           ?GetInfo@oCInfoManager@@QAEPAVoCInfo@@PAVoCNpc@@0H@Z
          const int oCInfoManager__GetInfo_G1 = 6704720;
    
    
          //0x00702D60 public: class oCInfo * __thiscall oCInfoManager::GetInfo(class oCNpc *,class oCNpc *,int)
          const int oCInfoManager__GetInfo_G2 = 7351648;
        
          var int oCInfoManager__GetInfo;
          oCInfoManager__GetInfo = MEMINT_SwitchG1G2(oCInfoManager__GetInfo_G1, oCInfoManager__GetInfo_G2);
    
    
          var oCNpc slf;    slf = Hlp_GetNpc (npcInstance);
          var oCNpc her;    Her = Hlp_GetNpc (herInstance);
    
    
          CALL_IntParam (index);
          CALL_PtrParam (MEM_InstToPtr (slf));
          CALL_PtrParam (MEM_InstToPtr (Her));
          CALL__thiscall (MEM_Game.infoman, oCInfoManager__GetInfo);
    
    
          return CALL_RetValAsPtr();
    };
    */
    
    
    FUNC INT oCInfoManager_GetInfoUnimportant (var int npcInstance, var int herInstance, var int index) //oCInfo *
    {
           //00665120  .text     Debug data           ?GetInfoUnimportant@oCInfoManager@@QAEPAVoCInfo@@PAVoCNpc@@0H@Z
           const int oCInfoManager__GetInfoUnimportant_G1 = 6705440;
    
    
          //0x00703030 public: class oCInfo * __thiscall oCInfoManager::GetInfoUnimportant(class oCNpc *,class oCNpc *,int)
           const int oCInfoManager__GetInfoUnimportant_G2 = 7352368;
    
    
           var int oCInfoManager__GetInfoUnimportant;
           oCInfoManager__GetInfoUnimportant = MEMINT_SwitchG1G2(oCInfoManager__GetInfoUnimportant_G1, oCInfoManager__GetInfoUnimportant_G2);
    
    
           var oCNpc slf;    slf = Hlp_GetNpc (npcInstance);
           var oCNpc her;    Her = Hlp_GetNpc (herInstance);
    
    
           CALL_IntParam (index);
           CALL_PtrParam (MEM_InstToPtr (slf));
           CALL_PtrParam (MEM_InstToPtr (Her));
           CALL__thiscall (MEM_Game.infoman, oCInfoManager__GetInfoUnimportant);
    
    
           return CALL_RetValAsPtr();
    };
    
    
    /* R  G  B  A
        FF FF FF FF */
    FUNC INT HEX2RGBA (var string hex)
    {
           var int R; R = 255;
           var int G; G = 255;
           var int B; B = 255;
           var int A; A = 255;
    
    
           if (STR_Len(hex) > 1)    {    R = hex2dec (STR_SubStr (hex, 0, 2));        };
           if (STR_Len(hex) > 3)    {    G = hex2dec (STR_SubStr (hex, 2, 2));        };
           if (STR_Len(hex) > 5)    {    B = hex2dec (STR_SubStr (hex, 4, 2));        };
           if (STR_Len(hex) > 7)    {    A = hex2dec (STR_SubStr (hex, 6, 2));        };
    
    
           return RGBA (R, G, B, A);
    };
    
    
    //0072BE90  .text     Debug data           ?Update@oCInformationManager@@QAIXXZ
    const int oCInformationManager__Update_G1    = 7519888;
    //0x00660BB0 public: void __fastcall oCInformationManager::Update(void)
    const int oCInformationManager__Update_G2    = 6687664;
    
    
    //00758A60  .text     Debug data           ?HandleEvent@zCViewDialogChoice@@UAEHH@Z
    const int zCViewDialogChoice__HandleEvent_G1    = 7703136;
    //0x0068EBA0 public: virtual int __thiscall zCViewDialogChoice::HandleEvent(int)
    const int zCViewDialogChoice__HandleEvent_G2    = 6876064;
    
    
    FUNC VOID _HOOK_VIEWDIALOGCHOICE_HANDLEEVENT ()
    {
           //'Refresh' dialogs (in case that there is just 1 dialog choice)
           InfoManagerUpdateState = cIM2BChanged;
    
    
           var int key; key = EDI;
           var int cancel; cancel = FALSE;
    
    
          //Work with input only in case InfoManager is waiting for an input
          if (MEM_InformationMan.IsWaitingForSelection) {
    
    
    //--- Answers -->
    
    
                 //InfoManagerAnswerPossible is set by _HOOK_INFORMATIONMANAGER_UPDATE
                  if (InfoManagerAnswerPossible)
                 {
                        //Cancel answer mode
                        if (key == KEY_ESCAPE) {
                               InfoManagerAnswerMode = FALSE;
                               InfoManagerAnswer = "";
                        };
    
    
                        //Enter answer mode / confirm answer
                        if (key == KEY_RETURN) {
                               //If answer mode was not enabled
                               if (!InfoManagerAnswerMode) {
                                      //Reset answer
                                      InfoManagerAnswer = "";
                               };
    
    
                               //on/off
                               InfoManagerAnswerMode = !InfoManagerAnswerMode;
                        };
    
    
                        var string s; s = "";
    
    
                        if (InfoManagerAnswerMode) {
                               var int shift;
                               shift = (MEM_KeyState (KEY_LSHIFT) == KEY_PRESSED) | (MEM_KeyState (KEY_LSHIFT) == KEY_HOLD) | (MEM_KeyState (KEY_RSHIFT) == KEY_PRESSED) | (MEM_KeyState (KEY_RSHIFT) == KEY_HOLD);
    
    
                               if (key == KEY_1) { if (shift) { s = "!"; } else { s = "1"; }; };
                               if (key == KEY_2) { if (shift) { s = "@"; } else { s = "2"; }; };
                               if (key == KEY_3) { if (shift) { s = "#"; } else { s = "3"; }; };
                               if (key == KEY_4) { if (shift) { s = "$"; } else { s = "4"; }; };
                               if (key == KEY_5) { if (shift) { s = "%"; } else { s = "5"; }; };
                               if (key == KEY_6) { if (shift) { s = "^"; } else { s = "6"; }; };
                               if (key == KEY_7) { if (shift) { s = "&"; } else { s = "7"; }; };
                               if (key == KEY_8) { if (shift) { s = "*"; } else { s = "8"; }; };
                               if (key == KEY_9) { if (shift) { s = "("; } else { s = "9"; }; };
                               if (key == KEY_0) { if (shift) { s = ")"; } else { s = "0"; }; };
    
    
                               if (key == KEY_MINUS) { if (shift) { s = "-"; } else { s = "_"; }; };
                               if (key == KEY_EQUALS) { if (shift) { s = "+"; } else { s = "="; }; };
    
    
                               //Backspace
                               if (key == KEY_BACK) {
                                      var int len;
                                      len = STR_Len (InfoManagerAnswer);
    
    
                                      if (len == 1) {
                                               InfoManagerAnswer = "";
                                      } else
                                      if (len > 1) {
                                             InfoManagerAnswer = STR_SubStr (InfoManagerAnswer, 0, len - 1);                    
                                      };
                               };
    
    
                               if (key == KEY_Q) { if (shift) { s = "Q"; } else { s = "q"; }; };
                               if (key == KEY_W) { if (shift) { s = "W"; } else { s = "w"; }; };
                               if (key == KEY_E) { if (shift) { s = "E"; } else { s = "e"; }; };
                               if (key == KEY_R) { if (shift) { s = "R"; } else { s = "r"; }; };
                               if (key == KEY_T) { if (shift) { s = "T"; } else { s = "t"; }; };
                               if (key == KEY_Y) { if (shift) { s = "Y"; } else { s = "y"; }; };
                               if (key == KEY_U) { if (shift) { s = "U"; } else { s = "u"; }; };
                               if (key == KEY_I) { if (shift) { s = "I"; } else { s = "i"; }; };
                               if (key == KEY_O) { if (shift) { s = "O"; } else { s = "o"; }; };
                               if (key == KEY_P) { if (shift) { s = "P"; } else { s = "p"; }; };
    
    
                               if (key == KEY_LBRACKET) { if (shift) { s = "{"; } else { s = "["; }; };
                               if (key == KEY_RBRACKET) { if (shift) { s = "}"; } else { s = "]"; }; };
    
    
                               if (key == KEY_A) { if (shift) { s = "A"; } else { s = "a"; }; };
                               if (key == KEY_S) { if (shift) { s = "S"; } else { s = "s"; }; };
                               if (key == KEY_D) { if (shift) { s = "D"; } else { s = "d"; }; };
                               if (key == KEY_F) { if (shift) { s = "F"; } else { s = "f"; }; };
                               if (key == KEY_G) { if (shift) { s = "G"; } else { s = "g"; }; };
                               if (key == KEY_H) { if (shift) { s = "H"; } else { s = "h"; }; };
                               if (key == KEY_J) { if (shift) { s = "J"; } else { s = "j"; }; };
                               if (key == KEY_K) { if (shift) { s = "K"; } else { s = "k"; }; };
                               if (key == KEY_L) { if (shift) { s = "L"; } else { s = "l"; }; };
    
    
                               if (key == KEY_SEMICOLON) { if (shift) { s = ":"; } else { s = ";"; }; };
                               if (key == KEY_APOSTROPHE) { if (shift) {
                                      //Double quote
                                      const int mem = 0;
    
    
                                      if (!mem) { mem = MEM_Alloc(1); };
    
    
                                      MEM_WriteByte (mem, 34);
                    
                                      s = STR_FromChar (mem);
                               } else { s = "'"; }; };
    
    
                               if (key == KEY_GRAVE) { if (shift) { s = "~"; } else { s = "`"; }; };
                               if (key == KEY_BACKSLASH) { if (shift) { s = "|"; } else { s = "\"; }; };
    
    
                               if (key == KEY_Z) { if (shift) { s = "Z"; } else { s = "z"; }; };
                               if (key == KEY_X) { if (shift) { s = "X"; } else { s = "x"; }; };
                               if (key == KEY_C) { if (shift) { s = "C"; } else { s = "c"; }; };
                               if (key == KEY_V) { if (shift) { s = "V"; } else { s = "v"; }; };
                               if (key == KEY_B) { if (shift) { s = "B"; } else { s = "b"; }; };
                               if (key == KEY_N) { if (shift) { s = "N"; } else { s = "n"; }; };
                               if (key == KEY_M) { if (shift) { s = "M"; } else { s = "m"; }; };
    
    
                               if (key == KEY_COMMA) { if (shift) { s = "<"; } else { s = ","; }; };
                               if (key == KEY_PERIOD) { if (shift) { s = ">"; } else { s = "."; }; };
                               if (key == KEY_SLASH) { if (shift) { s = "?"; } else { s = "/"; }; };
    
    
                               if (key == KEY_SPACE) { s = " "; };
    
    
                               if (key == KEY_NUMPAD0) { s = "0"; };
                               if (key == KEY_NUMPAD1) { s = "1"; };
                               if (key == KEY_NUMPAD2) { s = "2"; };
                               if (key == KEY_NUMPAD3) { s = "3"; };
                               if (key == KEY_NUMPAD4) { s = "4"; };
                               if (key == KEY_NUMPAD5) { s = "5"; };
                               if (key == KEY_NUMPAD6) { s = "6"; };
                               if (key == KEY_NUMPAD7) { s = "7"; };
                               if (key == KEY_NUMPAD8) { s = "8"; };
                               if (key == KEY_NUMPAD9) { s = "9"; };
    
    
                               if (key == KEY_MULTIPLY) { s = "*"; };
                               if (key == KEY_SUBTRACT) { s = "-"; };
                               if (key == KEY_ADD) { s = "+"; };
                               if (key == KEY_DECIMAL) { s = "."; };
    
    
                               if (STR_Len (s) > 0) {
                                       InfoManagerAnswer = ConcatStrings (InfoManagerAnswer, s);
                               };
    
    
                               cancel = TRUE; //Cancel input
                         };
                  };
    
    
    //--- Spinners -->
    
    
                 if (InfoManagerSpinnerPossible) {
                         //Default value if not set
                         if (InfoManagerSpinnerPageSize == 0) { InfoManagerSpinnerPageSize = 1; };
    
    
                        //Home
                         if (key == KEY_HOME) {
                                InfoManagerSpinnerValue = InfoManagerSpinnerValueMin;
                                cancel = TRUE;
                         };
    
    
                         //End
                         if (key == KEY_END) {
                                InfoManagerSpinnerValue = InfoManagerSpinnerValueMax;
                                cancel = TRUE;
                         };
    
    
                        //Page Up
                         if (key == KEY_PRIOR) {
                                //12 --> 10 --> 5 --> 1 --> 12
                                if (InfoManagerSpinnerValue > InfoManagerSpinnerValueMin) {
                                       if (((InfoManagerSpinnerValue / InfoManagerSpinnerPageSize) * InfoManagerSpinnerPageSize) < InfoManagerSpinnerValue) {
                                              InfoManagerSpinnerValue = (InfoManagerSpinnerValue / InfoManagerSpinnerPageSize) * InfoManagerSpinnerPageSize;
                                       } else {
                                              InfoManagerSpinnerValue -= InfoManagerSpinnerPageSize;
                                       };
    
    
                                      if (InfoManagerSpinnerValue < InfoManagerSpinnerValueMin) {
                                              InfoManagerSpinnerValue = InfoManagerSpinnerValueMin;
                                       };
                                } else {
                                       InfoManagerSpinnerValue -= InfoManagerSpinnerPageSize;
                                };
    
    
                               cancel = TRUE;
                         };
    
    
                         //Page Down
                         if (key == KEY_NEXT) {
                                //1 --> 5 --> 10 --> 12 --> 1
                                if (InfoManagerSpinnerValue < InfoManagerSpinnerValueMax) {
                                       InfoManagerSpinnerValue = (InfoManagerSpinnerValue / InfoManagerSpinnerPageSize) * InfoManagerSpinnerPageSize;
                                       InfoManagerSpinnerValue += InfoManagerSpinnerPageSize;
    
    
                                      if (InfoManagerSpinnerValue > InfoManagerSpinnerValueMax) {
                                              InfoManagerSpinnerValue = InfoManagerSpinnerValueMax;
                                       };
                                } else {
                                       InfoManagerSpinnerValue += InfoManagerSpinnerPageSize;
                                };
    
    
                                cancel = TRUE;
                         };
    
    
                        if (key == KEY_LEFTARROW) {
                                InfoManagerSpinnerValue -= 1;
                                cancel = TRUE;
                         };
    
    
                         if (key == KEY_RIGHTARROW) {
                                InfoManagerSpinnerValue += 1;
                                cancel = TRUE; //Cancel input (just in case)
                         };
    
    
                        if (cancel) {
                                //Min/Max values
                                if (InfoManagerSpinnerValue < InfoManagerSpinnerValueMin) {
                                       InfoManagerSpinnerValue = InfoManagerSpinnerValueMax;
                                };
    
    
                                if (InfoManagerSpinnerValue > InfoManagerSpinnerValueMax) {
                                       InfoManagerSpinnerValue = InfoManagerSpinnerValueMin;
                                };
                         };
                  };
          };
    
    
           //Cancel input if InfoManager is waiting for anything
          if (MEM_InformationMan.IsWaitingForEnd)
          || (MEM_InformationMan.IsWaitingForOpen)
          || (MEM_InformationMan.IsWaitingForClose)
    //       || (MEM_InformationMan.IsWaitingForScript) this would prevent us from cancelling output units
          {
                 cancel = TRUE;
          };
    
    
    
    
           if (cancel) {
                  EDI = 0;
                  MEM_WriteInt (ESP + 4, 0);
           };
    };
    
    
    FUNC VOID _HOOK_INFORMATIONMANAGER_UPDATE ()
    {    
           var zCViewDialogChoice dlg; dlg = _^(MEM_InformationMan.DlgChoice);
    
    
    /*
              if (dlg.IsActivated == 1)
              && (dlg.IsOpen == 1)
              && (dlg.ChoiceSelected > -1)
              {
    */
    
    
          var int choiceView; choiceView = MEM_InformationMan.DlgChoice;
    
    
          var zCArray arr;
    
    
          var zCViewText2 txt;
          var zCViewText2 txtIndicator;
    
    
          //Remove added 'Indicator' dialogs
          if (Hlp_StrCmp (MEM_InformationMan.LastMethod, "CollectInfos")) {
                 if (InfoManagerAnswerIndicator) {
                        //Is there an extra dialog ?
                        if (dlg.m_listLines_numInArray > dlg.Choices) {
                               arr = _^ (choiceView + 172);
    
    
                               if (arr.array) {
                                      txtIndicator = _^ (MEM_ReadIntArray (arr.array, dlg.m_listLines_numInArray - 1));
                                      //add remove flag - Gothic will take care of the rest
                                      txtIndicator.remove = TRUE;
                               };
                        };
    InfoManagerAnswerIndicator = 0;
                 };
    
    
                 //Is there an extra dialog ?
                 if (InfoManagerSpinnerIndicator) {
                        if (dlg.m_listLines_numInArray > dlg.Choices) {
                               arr = _^ (choiceView + 172);
                               if (arr.array) {
                                      txtIndicator = _^ (MEM_ReadIntArray (arr.array, dlg.m_listLines_numInArray - 1));
                                      //add remove flag - Gothic will take care of the rest
                                      txtIndicator.remove = TRUE;
                               };
                        };
    InfoManagerSpinnerIndicator = 0;
                 };
          };
    
    
           if (dlg.IsActivated == 1)
          {
                  if (InfoManagerUpdateState == cIM2BChanged)
                  || (InfoManagerLastChoiceSelected != dlg.ChoiceSelected)
                  {
                         //Reset by default, script will figure out whether Answer is possible below, when it updates all dialog descriptions
                         InfoManagerAnswerPossible = FALSE;
                        //Reset by default, script will figure out whether Spinning is poosible below, when it updates all dialog descriptions
                         InfoManagerSpinnerPossible = FALSE;
    
    
                         arr = _^ (choiceView + 172);
                         if (arr.array) {
                                var int nextPosY; nextPosY = 0;
    
    
                                //loop counter for dialog options in zCViewDialogChoice
                                var int i; i = 0;
                                var int p;
    
    
                                var string dlgFont;
    
    
                                p = MEM_StackPos.position;
                    
                                if (i < dlg.Choices) {
                                       txt = _^ (MEM_ReadIntArray(arr.array, i));
                        
                                       //Get current fontame
                                       dlgFont = Print_GetFontName (txt.font);
    
    
                                       //Get current dialog instance
                                       var C_NPC slf; slf = _^ (MEM_InformationMan.npc);
                                       var C_NPC her; her = _^ (MEM_InformationMan.player);
    
    
                                       var int infoPtr; infoPtr = 0;
    
    
                                       var oCInfo dlgInstance;
    
    
                                       const int cINFO_MGR_MODE_IMPORTANT    = 0;
                                       const int cINFO_MGR_MODE_INFO        = 1;
                                       const int cINFO_MGR_MODE_CHOICE        = 2;
                                       const int cINFO_MGR_MODE_TRADE        = 3;
    
    
                                       //'Standard' dialog options
                                       if (MEM_InformationMan.Mode == cINFO_MGR_MODE_INFO) {
                                              infoPtr = oCInfoManager_GetInfoUnimportant (slf, her, i);
                                       } else
                                       //Choices - have to be extracted from oCInfo.listChoices_next
                                       //MEM_InformationMan.Info is a pointer to oCInfo
                                       if (MEM_InformationMan.Mode == cINFO_MGR_MODE_CHOICE) {
                                              infoPtr = MEM_InformationMan.Info;
                                       };
    
    
                                       if (infoPtr) {
                                              var int len;
                                              var int index;
    
    
                                              var string dlgDescription;
    
    
                                              //Default colors
                                              var string dlgColor; dlgColor = InfoManagerDefaultColorDialogGrey;
                                              var string dlgColorSelected; dlgColorSelected = InfoManagerDefaultDialogColorSelected;
    
    
                                              var string dlgFontSelected; dlgFontSelected = "";
                            
                                              //Get description from dialogInstance.description
                                              dlgInstance = _^ (infoPtr);
                                              dlgDescription = dlgInstance.description;
    
    
                                              //Choices
                                              if (MEM_InformationMan.Mode == cINFO_MGR_MODE_CHOICE) {
                                                     if (dlgInstance.listChoices_next) {
                                                           //loop counter for all Choices
                                                           var int j; j = 0;
    
    
                                                           var zCList l;
                                                           var int list; list = dlgInstance.listChoices_next;
                                                           while (list);
                                                                  l = _^(list);
                                                                  var oCInfoChoice dlgChoice; dlgChoice = MEM_PtrToInst (l.data);
    
    
                                                                  //if our dialog option is dialog choice - put text to dlgDescription
                                                                  if (i == j) {
                                                                         dlgDescription = dlgChoice.Text;
                                                                  };
    
    
                                                                  list = l.next;
                                                                  j += 1;
                                                           end;
                                                     };
                                              };
    
    
                                              /* Extract font, font selected, color and color selected from dlgDescription.
                                                  Clear dlgDescription in process. */
    
    
                                              //Extract font name
                                              if (STR_StartsWith (dlgDescription, "f@")) {
                                                     len = STR_Len (dlgDescription);
                                                     len -= 2;
    
    
                                                     dlgDescription = STR_SubStr (dlgDescription, 2, len);
                                                     index = STR_IndexOf (dlgDescription, " ");
    
    
                                                     if (index > 0) {
                                                            len = STR_Len (dlgDescription);
                                                            len -= (index + 1);
    
    
                                                            dlgFont = STR_Prefix (dlgDescription, index);
                                                            dlgDescription = STR_SubStr (dlgDescription, index + 1, len);
                                                     };
                                              };
    
    
                                              //Extract font selected name
                                              if (STR_StartsWith (dlgDescription, "fs@")) {
                                                     len = STR_Len (dlgDescription);
                                                     len -= 3;
    
    
                                                     dlgDescription = STR_SubStr (dlgDescription, 3, len);
                                                     index = STR_IndexOf (dlgDescription, " ");
    
    
                                                     if (index > 0) {
                                                            len = STR_Len (dlgDescription);
                                                            len -= (index + 1);
                                    
                                                            dlgFontSelected = STR_Prefix (dlgDescription, index);
                                                            dlgDescription = STR_SubStr (dlgDescription, index + 1, len);
                                                     };
                                              };
                            
                                              //Extract color grayed
                                              if (STR_StartsWith (dlgDescription, "h@")) {
                                                     len = STR_Len (dlgDescription);
                                                     len -= 2;
    
    
                                                     dlgDescription = STR_SubStr (dlgDescription, 2, len);
                                                     index = STR_IndexOf (dlgDescription, " ");
    
    
                                                     if (index > 0) {
                                                            len = STR_Len (dlgDescription);
                                                            len -= (index + 1);
    
    
                                                            dlgColor = STR_Prefix (dlgDescription, index);
                                                            dlgDescription = STR_SubStr (dlgDescription, index + 1, len);
                                                     };
                                              };
    
    
                                              //Extract color selected
                                              if (STR_StartsWith (dlgDescription, "hs@")) {
                                                     len = STR_Len (dlgDescription);
                                                     len -= 3;
    
    
                                                     dlgDescription = STR_SubStr (dlgDescription, 3, len);
                                                     index = STR_IndexOf (dlgDescription, " ");
    
    
                                                     if (index > 0) {
                                                            len = STR_Len (dlgDescription);
                                                            len -= (index + 1);
    
    
                                                            dlgColorSelected = STR_Prefix (dlgDescription, index);
                                                            dlgDescription = STR_SubStr (dlgDescription, index + 1, len);
                                                     };
                                              };
    
    
                                              var int alignment; alignment = InfoManagerDefaultDialogAlignment;
                                              var int textWidth;
    
    
                                             //al@ align left
                                              if (STR_StartsWith (dlgDescription, "al@")) {
                                                     len = STR_Len (dlgDescription);
                                                     len -= 4;
                                                     dlgDescription = STR_SubStr (dlgDescription, 4, len);
    
    
                                                     alignment = 0;
                                              };
    
    
                                              //ac@ align center
                                              if (STR_StartsWith (dlgDescription, "ac@")) {
                                                     len = STR_Len (dlgDescription);
                                                     len -= 4;
                                                     dlgDescription = STR_SubStr (dlgDescription, 4, len);
    
    
                                                     alignment = 1;
                                              };
    
    
                                             //ar@ align right
                                              if (STR_StartsWith (dlgDescription, "ar@")) {
                                                     len = STR_Len (dlgDescription);
                                                     len -= 4;
                                                     dlgDescription = STR_SubStr (dlgDescription, 4, len);
    
    
                                                     alignment = 2;
                                              };
    
    
                                              var int answerDialog; answerDialog = -1;
                            
                                              //answer
                                              if (STR_StartsWith (dlgDescription, "a@")) {
                                                     len = STR_Len (dlgDescription);
                                                     len -= 3;
                                                     dlgDescription = STR_SubStr (dlgDescription, 3, len);
    
    
                                                     answerDialog = i;
                                              };
                            
                                              var int spinnerDialog; spinnerDialog = -1;
                                              var string spinnerDialogID; spinnerDialogID = "";
    
    
                                              //spinner s@
                                              if (STR_StartsWith (dlgDescription, "s@")) {
                                                     len = STR_Len (dlgDescription);
                                                     len -= 2;
                                                     dlgDescription = STR_SubStr (dlgDescription, 2, len);
    
    
                                                     index = STR_IndexOf (dlgDescription, " ");
    
    
                                                     if (index > 0) {
                                                            len = STR_Len (dlgDescription);
                                                            len -= (index + 1);
    
    
                                                            spinnerDialogID = STR_Prefix (dlgDescription, index);
                                                            dlgDescription = STR_SubStr (dlgDescription, index + 1, len);
                                                     };
    
    
                                                     spinnerDialog = i;
                                              };
    
    
                                              //Apply dlgColor and dlgColorSelected --> Is current dialog choice selected one ?
                                              if (i == dlg.ChoiceSelected) {
                                                     if (answerDialog == i) {
                                                            InfoManagerAnswerPossible = TRUE;
    
    
                                                            //Add answer indicator
                                                            if (!InfoManagerAnswerMode) {
                                                                   if (!InfoManagerAnswerIndicator) {
                                                                          txt.useAlpha = TRUE;
                                                                          txt.alphaFunc = 1;
                                                                          txt.alpha = 255;
    
    
                                                                          //Create new zCViewText2 instance for our indicator
                                                                          InfoManagerAnswerIndicator = create (zCViewText2@);
                                                                          txtIndicator = _^ (InfoManagerAnswerIndicator);
    
    
                                                                          //Insert indicator to dialog choices
                                                                          MEM_ArrayInsert (choiceView + 172, InfoManagerAnswerIndicator); 
    
    
                                                                          txtIndicator.validcolor = txt.validcolor;
    
    
                                                                          txtIndicator.useAlpha = txt.useAlpha;
                                                                          txtIndicator.alphaFunc = txt.alphaFunc;
                                                                          txtIndicator.alpha = 128;
    
    
                                                                          txtIndicator.text = "...";
                                                                   };
                                                            };
                                                    };
    
    
                                                     if (spinnerDialog == i) {
                                                            InfoManagerSpinnerPossible = TRUE;
                                                            InfoManagerSpinnerID = spinnerDialogID;
    
    
                                                            //Add spinner indicator
                                                            if (!InfoManagerSpinnerIndicator) {
                                                                   txt.useAlpha = TRUE;
                                                                   txt.alphaFunc = 1;
                                                                   txt.alpha = 255;
    
    
                                                                   //Create new zCViewText2 instance for our indicator
                                                                   InfoManagerSpinnerIndicator = create (zCViewText2@);
                                                                   txtIndicator = _^ (InfoManagerSpinnerIndicator);
    
    
                                                                   //Insert indicator to dialog choices
                                                                   MEM_ArrayInsert (choiceView + 172, InfoManagerSpinnerIndicator); 
    
    
                                                                   txtIndicator.validcolor = txt.validcolor;
    
    
                                                                   txtIndicator.useAlpha = txt.useAlpha;
                                                                   txtIndicator.alphaFunc = txt.alphaFunc;
                                                                   txtIndicator.alpha = 128;
    
    
                                                                   txtIndicator.text = "<>";
                                                            };
                                                     };
    
    
                                                     if (STR_Len (dlgColorSelected) > 0) {
                                                            txt.color = HEX2RGBA (dlgColorSelected);
                                                     };
    
    
                                                     if (STR_Len (dlgFontSelected) > 0) {
                                                            dlgFont = dlgFontSelected;
                                                     };
    
    
                                                    //Are we in answer mode? If yes replace description with current answer
                                                     if (InfoManagerAnswerMode) {
                                                            dlgDescription = ConcatStrings (InfoManagerAnswer, "_");
                                                     };
                                             } else {
                                                     if (STR_Len (dlgColor) > 0) {
                                                            txt.color = HEX2RGBA (dlgColor);
                                                     };
                                              };
    
    
                                              //Replace dialog option text with 'cleared' dlgDescription
                                              txt.text = dlgDescription;
    
    
                                              //Alignment: 0 left, 1 center, 2 right
                                              if (alignment == 0) {
                                                     txt.posx = txt.posx + dlg.offsetTextpx;
                                              } else
                                              if (alignment == 1) {
                                                     textWidth = Print_GetStringWidth (dlgDescription, dlgFont);
                                                     txt.posx = (dlg.psizex / 2) - (textWidth / 2) - dlg.offsetTextpx - dlg.sizeMargin_0;
                                              } else
                                              if (alignment == 2) {
                                                     textWidth = Print_GetStringWidth (dlgDescription, dlgFont);
                                                     txt.posx = dlg.psizex - textWidth - dlg.offsetTextpx - dlg.sizeMargin_0;
                                              };
                                       };
    
    
                                       //Recalculate offsetTextpy and posY for dialog items in case fonts changed
                                       if (i == 0) {
                                              nextPosY = txt.posY;
                                              dlg.offsetTextpy = 0;
                                       } else {
                                              txt.posY = nextPosY;
                                       };
    
    
                                       var int newFont; newFont = Print_GetFontPtr (dlgFont);
    
    
                                      //Adjust X, Y pos in case dialog with indicators is selected
                                       if (i == dlg.ChoiceSelected) {
                                              if (InfoManagerAnswerIndicator) {
                                                     txtIndicator = _^ (InfoManagerAnswerIndicator);
    
    
                                                     if (answerDialog == i) {
                                                            txtIndicator.font = newFont;
                                                            txtIndicator.color = HEX2RGBA (dlgColor);
    
    
                                                            txtIndicator.posy = txt.posy;
    
    
                                                            textWidth = Print_GetStringWidth (txtIndicator.text, dlgFont);
                                                            txtIndicator.posx = dlg.psizex - textWidth - dlg.offsetTextpx - dlg.sizeMargin_0;
                                                     };
                                              };
    
    
                                             if (InfoManagerSpinnerIndicator) {
                                                     txtIndicator = _^ (InfoManagerSpinnerIndicator);
    
    
                                                    if (spinnerDialog == i) {
                                                            txtIndicator.font = newFont;
                                                            txtIndicator.color = HEX2RGBA (dlgColor);
    
    
                                                            txtIndicator.posy = txt.posy;
    
    
                                                            textWidth = Print_GetStringWidth (txtIndicator.text, dlgFont);
                                                            txtIndicator.posx = dlg.psizex - textWidth - dlg.offsetTextpx - dlg.sizeMargin_0;
                                                     };
                                              };
                                       };
    
    
                                       if (i < dlg.LineStart) {
                                              dlg.offsetTextpy -= Print_GetFontHeight (dlgFont);
                                       };
    
    
                                       //Apply new font (or re-apply old one)
                                       txt.font = newFont;
    
    
                                       nextPosY += Print_GetFontHeight (dlgFont);
    
    
                                       i += 1;
                                       MEM_StackPos.position = p;
                                };
                         } else {
                                InfoManagerUpdateState = cIMChanged;
                                InfoManagerLastChoiceSelected = dlg.ChoiceSelected;
                         };
                  };
           };
    
    
    /*
          } else {
                 InfoManagerUpdateState = cIM2BChanged;
          }; 
    */
    
    
          //Remove if not required (or if we are already answering)
          if (!InfoManagerAnswerPossible) || (InfoManagerAnswerMode) {
                if (InfoManagerAnswerIndicator) {
                      //Is there an extra dialog ?
                      if (dlg.m_listLines_numInArray > dlg.Choices) {
                            arr = _^ (choiceView + 172);
    
    
                            if (arr.array) {
                                  txtIndicator = _^ (MEM_ReadIntArray (arr.array, dlg.m_listLines_numInArray - 1));
                                  //add remove flag - Gothic will take care of the rest
                                  txtIndicator.remove = TRUE;
                            };
                      };
                      InfoManagerAnswerIndicator = 0;
                };
          };
    
    
         //Remove if not required
          if (!InfoManagerSpinnerPossible) {
                if (InfoManagerSpinnerIndicator) {
                      //Is there an extra dialog ?
                      if (dlg.m_listLines_numInArray > dlg.Choices) {
                            arr = _^ (choiceView + 172);
    
    
                            if (arr.array) {
                                  txtIndicator = _^ (MEM_ReadIntArray (arr.array, dlg.m_listLines_numInArray - 1));
                                  //add remove flag - Gothic will take care of the rest
                                  txtIndicator.remove = TRUE;
                            };
                      };
                      InfoManagerSpinnerIndicator = 0;
                };
          };
    };

    Hook it with:
    Code:
        HookEngine (MEMINT_SwitchG1G2 (oCInformationManager__Update_G1, oCInformationManager__Update_G2), 5, "_HOOK_INFORMATIONMANAGER_UPDATE");
        HookEngine (MEMINT_SwitchG1G2 (zCViewDialogChoice__HandleEvent_G1, zCViewDialogChoice__HandleEvent_G2), 9, "_HOOK_VIEWDIALOGCHOICE_HANDLEEVENT");
    Dialogs which I have used for testing purposes:
    Code:
    /******************************************************
        TEST SCENARIOS:
        1. Instances are not 'sorted' first instance is the one with nr 2
        2. 1 dialog Instance will not be displayed, as condition will return FALSE
        3. 1 dialog Instance will clear dialog options (Info_ClearChoices) and add choices instead (Info_AddChoice)
        4. 1 dialog Instance description will be changed on the run in condition function
        5. we will have more dialog options which will have to be scrolled down to
    ******************************************************/
    FUNC INT Always_True () { return TRUE; };
    FUNC INT Always_False () { return FALSE; };
    FUNC VOID DIA_DO_NOTHING () {};
    
    INSTANCE DIA_TestDialog_Orange (C_Info) {
           nr              = 2;
           npc             = GRD_1650_Gardist;
           condition       = DIA_TestDialog_Orange_Condition;
           information     = DIA_DO_NOTHING;
           permanent       = FALSE;
           description     = "dummy";
    };
    
    FUNC INT DIA_TestDialog_Orange_Condition () {
           //Test scenario - adjust description on the run
           DIA_TestDialog_Orange.description = "f@font_15_white.tga fs@font_old_20_white.tga h@FF8000 hs@FFB266 Orange !"; //orange, selected: Light orange
           return TRUE;
    };
    
    INSTANCE DIA_TestDialog_Line01 (C_Info) {
           nr              = 1;
           npc             = GRD_1650_Gardist;
           condition       = Always_True;
           information     = DIA_DO_NOTHING;
           permanent       = FALSE;
           description     = "Line 1";
    };
    
    INSTANCE DIA_TestDialog_Line03 (C_Info) {
           nr              = 3;
           npc             = GRD_1650_Gardist;
           condition       = Always_True;
           information     = DIA_DO_NOTHING;
           permanent       = FALSE;
           description     = "Line 3";
    };
    
    INSTANCE DIA_TestDialog_Line04 (C_Info) {
           nr              = 4;
           npc             = GRD_1650_Gardist;
           condition       = Always_True;
           information     = DIA_DO_NOTHING;
           permanent       = FALSE;
           description     = "Line 4";
    };
    
    INSTANCE DIA_TestDialog_Standard04 (C_Info) {
           nr              = 6;
           npc             = GRD_1650_Gardist;
           condition       = Always_True;
           information     = DIA_DO_NOTHING;
           permanent       = FALSE;
           description     = "Line 6";
    };
    
    INSTANCE DIA_TestDialog_Trade (C_Info) {
           nr              = 5;
           npc             = GRD_1650_Gardist;
           condition       = Always_True;
           information     = DIA_DO_NOTHING;
           permanent       = TRUE;
           trade           = TRUE;
           description     = "fs@font_15_white.tga h@FFFF00 hs@FF0000 Let's trade."; //defaultfont yellow, selected: fontsize 15 red
    };
    
    INSTANCE DIA_TestDialog_Choices (C_Info) {
           nr              = GRD_1650_Gardist;
           nr              = 8;
           condition       = Always_True;
           information     = DIA_TestDialog_Choices_Test;
           permanent       = TRUE;
           description     = "Choices - test";
    };
    
    FUNC VOID DIA_TestDialog_Choices_Test () {
           Info_ClearChoices (DIA_TestDialog_Choices);
           Info_AddChoice (DIA_TestDialog_Choices, "Standard.", DIA_TestDialog_Choices_Test);
           Info_AddChoice (DIA_TestDialog_Choices, "h@00CC66 hs@66FFB2 Green.", DIA_TestDialog_Choices_Test);
           Info_AddChoice (DIA_TestDialog_Choices, "fs@font_15_white.tga Selected fontsize 15.", DIA_TestDialog_Choices_Test);
           Info_AddChoice (DIA_TestDialog_Choices, "BACK", DIA_TestDialog_Choices_Test_Back);
    };
    
    FUNC VOID DIA_TestDialog_Choices_Test_Back () {
           Info_ClearChoices (DIA_TestDialog_Choices);
    };
    
    INSTANCE DIA_TestDialog_NeverShown (C_Info) {
           nr              = 8;
           npc             = GRD_1650_Gardist;
           condition       = Always_False;
           information     = DIA_DO_NOTHING;
           permanent       = FALSE;
           description     = "This dialog option will never be displayed";
    };
    
    INSTANCE DIA_TestDialog_GreenColorNoFont (C_Info) {
           nr              = 9;
           npc             = GRD_1650_Gardist;
           condition       = Always_True;
           information     = DIA_DO_NOTHING;
           permanent       = FALSE;
           description     = "h@00CC66 hs@66FFB2 Green color."; //default font green, selected: light green
    };
    
    INSTANCE DIA_TestDialog_Exit (C_Info) {
           nr              = 999;
           npc             = GRD_1650_Gardist;
           condition       = Always_True;
           information     = Exit_Dialog;
           permanent       = TRUE;
           description     = "f@font_15_white.tga h@FFFFFF hs@FFFF00 Exit dialog."; //fontsize 15 white, selected: yellow
    };
    Let me know if you see any issues - this was not thoroughly tested - so it might not be 100 % working properly.
    Geändert von F a w k e s (30.09.2020 um 18:32 Uhr)

  2. Beiträge anzeigen #2 Zitieren
    Hero Avatar von lali
    Registriert seit
    Feb 2016
    Beiträge
    5.473
     
    lali ist offline
    Thats amazing. I am sure that we will use this in some way. Thank you for the work and documentation.
    Phoenix Dev | Website | Discord

  3. Beiträge anzeigen #3 Zitieren
    Local Hero
    Registriert seit
    Feb 2017
    Beiträge
    270
     
    F a w k e s ist offline
    I just fixed problem with delayed text update - code above updated

  4. Beiträge anzeigen #4 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Nice work! With appropriate/subtle enough colors, this looks like a cool feature.

  5. Beiträge anzeigen #5 Zitieren
    Moderator Avatar von ukur
    Registriert seit
    Jan 2009
    Ort
    Ukraine
    Beiträge
    281
     
    ukur ist offline
    Excellent.
    Is there a similar for adding colors to the strings of items in the inventory with examples?

  6. Beiträge anzeigen #6 Zitieren
    Local Hero
    Registriert seit
    Feb 2017
    Beiträge
    270
     
    F a w k e s ist offline
    Hello folks, quick update - had to add back condition checking if (dlg.IsActivated == 1) as sometimes Gothic crashed on me without it.
    Also fixed calculation for STR_SubStr - this led to warning:
    MEM_WARN('STR_SubStr: The end of the desired substring exceeds the end of the string.') + 21 bytes
    Code above update once again.

    Zitat Zitat von ukur Beitrag anzeigen
    Is there a similar for adding colors to the strings of items in the inventory with examples?
    That's something I wanted to implement as well, but I cannot figure out how to change color of inventory item overview

  7. Beiträge anzeigen #7 Zitieren
    Serima Avatar von Fisk2033
    Registriert seit
    Dec 2010
    Ort
    Dresden
    Beiträge
    5.803
     
    Fisk2033 ist offline
    Nice as always...really useful - thanks for sharing

  8. Beiträge anzeigen #8 Zitieren
    Local Hero
    Registriert seit
    Feb 2017
    Beiträge
    270
     
    F a w k e s ist offline

    Bugfix: replacing function oCInfoManager_GetInfo with oCInfoManager_GetInfoUnimportant

    Hello folks,
    Just recognized there is a rather rare bug - if NPC has assigned IMPORTANT dialog for which its condition would be fulfilled while you are in a dialog with NPC itself - this color-changing hooked function would completely mess up order of dialog choices. Only option would be to exit dialog, let the Important dialog play and then to open dialog choices again.
    I was able to fix this bug by replacing function oCInfoManager_GetInfo with function oCInfoManager_GetInfoUnimportant, which seems to be ignoring all 'IMPORTANT = TRUE' dialogs, and therefore seems to be working correctly for the purposes of this color-changing hook. Code above updated, changes highlighted with yellow color.

  9. Beiträge anzeigen #9 Zitieren
    Local Hero
    Registriert seit
    Feb 2017
    Beiträge
    270
     
    F a w k e s ist offline

    G1 dialog options effects

    Hello folks,
    I have been playing around with fonts and colors recently - and I wanted to add for Baal Netbek dialog option, which would be showing randomly generated strings.
    I was hoping for a cool effect, where part of a text would be readable, and part would be changing constantly - so player would be puzzled - not having a clue, what dialog choice is actually choosing.
    My problem is - seems like each letter of the font has different width - so it makes whole dialog option almost unreadable (3rd dialog option in the video below)
    Is there a simple way how to set font width for each letter to same size (maybe using some engine call)? Or do I have to create a completely new font for this?
    [Video]
    Code for these dialog options:
    Code:
    //http://www.perbang.dk/rgbgradient/
    FUNC STRING RainbowHexColor ()
    {
        var int indexMain;
        indexMain += 1;
        
        if (indexMain < 0)    {    indexMain = 1;        };
        if (indexMain > 256)    {    indexMain = 1;        };
    
        var int index;
        index = indexMain / 4;
    
        if (index < 1)        {    index = 1;        };
        if (index > 64)        {    index = 1;        };
        
        if (index == 1)        {    return    "1700D2";    };
        if (index == 2)        {    return    "0500D2";    };
        if (index == 3)        {    return    "000CD2";    };
        if (index == 4)        {    return    "001ED2";    };
        if (index == 5)        {    return    "0031D2";    };
        if (index == 6)        {    return    "0043D2";    };
        if (index == 7)        {    return    "0055D2";    };
        if (index == 8)        {    return    "0067D2";    };
        if (index == 9)        {    return    "0079D2";    };
        if (index == 10)    {    return    "008BD1";    };
        if (index == 11)    {    return    "009ED1";    };
    
        if (index == 12)    {    return    "00B0D1";    };
        if (index == 13)    {    return    "00C2D1";    };
        if (index == 14)    {    return    "00D1CE";    };
        if (index == 15)    {    return    "00D1BC";    };
        if (index == 16)    {    return    "00D1AA";    };
        if (index == 17)    {    return    "00D198";    };
        if (index == 18)    {    return    "00D185";    };
        if (index == 19)    {    return    "00D173";    };
        if (index == 20)    {    return    "00D061";    };
        if (index == 21)    {    return    "00D04F";    };
        if (index == 22)    {    return    "00D03D";    };
    
        if (index == 23)    {    return    "00D02B";    };
        if (index == 24)    {    return    "00D018";    };
        if (index == 25)    {    return    "00D006";    };
        if (index == 26)    {    return    "0BD000";    };
        if (index == 27)    {    return    "1DD000";    };
        if (index == 28)    {    return    "2FD000";    };
        if (index == 29)    {    return    "41CF00";    };
        if (index == 30)    {    return    "53CF00";    };
        if (index == 31)    {    return    "65CF00";    };
        if (index == 32)    {    return    "77CF00";    };
        if (index == 33)    {    return    "89CF00";    };
        
        if (index == 34)    {    return    "9ACF00";    };
        if (index == 35)    {    return    "ACCF00";    };
        if (index == 36)    {    return    "BECF00";    };
        if (index == 37)    {    return    "CFCD00";    };
        if (index == 38)    {    return    "CEBB00";    };
        if (index == 39)    {    return    "CEA900";    };
        if (index == 40)    {    return    "CE9700";    };
        if (index == 41)    {    return    "CE8500";    };
        if (index == 42)    {    return    "CE7300";    };
        if (index == 43)    {    return    "CE8100";    };
        if (index == 44)    {    return    "CE4F00";    };
    
        if (index == 45)    {    return    "CE3D00";    };
        if (index == 46)    {    return    "CE2B00";    };
        if (index == 47)    {    return    "CD1900";    };
        if (index == 48)    {    return    "CD0800";    };
        if (index == 49)    {    return    "CD0009";    };
        if (index == 50)    {    return    "CD001B";    };
        if (index == 51)    {    return    "CD002D";    };
        if (index == 52)    {    return    "CD003F";    };
        if (index == 53)    {    return    "CD0050";    };
        if (index == 54)    {    return    "CD0062";    };
        if (index == 55)    {    return    "CD0074";    };
    
        if (index == 56)    {    return    "CC0086";    };
        if (index == 57)    {    return    "CC0097";    };
        if (index == 58)    {    return    "CC00A9";    };
        if (index == 59)    {    return    "CC00BB";    };
        if (index == 60)    {    return    "CC00CC";    };
        if (index == 61)    {    return    "BA00CC";    };
        if (index == 62)    {    return    "A800CC";    };
        if (index == 63)    {    return    "9600CC";    };
        
        return "8400CC";
    };
    
    INSTANCE DIA_Netbek_Rainbow_Colors (C_Info)
    {
        nr        = 1;
        npc        = NOV_1371_BaalNetbek;
        condition    = DIA_Netbek_Rainbow_Colors_Condition;
        information    = DIA_Netbek_Rainbow_Colors_Info;
        important    = FALSE;
        permanent    = TRUE;
        description    = "dummy";
    };
    
    FUNC INT DIA_Netbek_Rainbow_Colors_Condition ()
    {
        var string newDescription; newDescription = "c#";
    
        newDescription = ConcatStrings (newDescription, RainbowHexColor ());
        newDescription = ConcatStrings (newDescription, " cs#");
        newDescription = ConcatStrings (newDescription, RainbowHexColor ());
        newDescription = ConcatStrings (newDescription, " Rainbow colors test");
        
        DIA_Netbek_Rainbow_Colors.description = newDescription;
        
        return TRUE;
    };
    
    FUNC VOID DIA_Netbek_Rainbow_Colors_Info ()
    {
    };
    
    //White 'blinking' fully visible - transparent 
    //R    G    B    A
    //FF    FF    FF    01 - FF
    FUNC STRING AlphaBlinkingHexColor ()
    {
        var int indexMain;
        indexMain += 1;
        
        if (indexMain < 0)    {    indexMain = 1;        };
        if (indexMain > 256)    {    indexMain = 1;        };
    
        var int index;
        
        index = indexMain / 4;
        
        if (index == 1)    {    return "FFFFFF01";    };
        if (index == 2)    {    return "FFFFFF09";    };
        if (index == 3)    {    return "FFFFFF11";    };
        if (index == 4)    {    return "FFFFFF19";    };
        if (index == 5)    {    return "FFFFFF21";    };
        if (index == 6)    {    return "FFFFFF29";    };
        if (index == 7)    {    return "FFFFFF31";    };
        if (index == 8)    {    return "FFFFFF39";    };
        if (index == 9)    {    return "FFFFFF41";    };
        if (index == 10){    return "FFFFFF49";    };
        if (index == 11){    return "FFFFFF51";    };
        if (index == 12){    return "FFFFFF59";    };
        if (index == 13){    return "FFFFFF61";    };
        if (index == 14){    return "FFFFFF69";    };
        if (index == 15){    return "FFFFFF71";    };
        if (index == 16){    return "FFFFFF79";    };
        if (index == 17){    return "FFFFFF81";    };
        if (index == 18){    return "FFFFFF89";    };
        if (index == 19){    return "FFFFFF91";    };
        if (index == 20){    return "FFFFFF99";    };
        if (index == 21){    return "FFFFFFA1";    };
        if (index == 22){    return "FFFFFFA9";    };
        if (index == 23){    return "FFFFFFB1";    };
        if (index == 24){    return "FFFFFFB9";    };
        if (index == 25){    return "FFFFFFC1";    };
        if (index == 26){    return "FFFFFFC9";    };
        if (index == 27){    return "FFFFFFD1";    };
        if (index == 28){    return "FFFFFFD9";    };
        if (index == 29){    return "FFFFFFE1";    };
        if (index == 30){    return "FFFFFFE9";    };
        if (index == 31){    return "FFFFFFF1";    };
        if (index == 32){    return "FFFFFFF9";    };
    //---    
        if (index == 33){    return "FFFFFFFF";    };
        if (index == 34){    return "FFFFFFF1";    };
        if (index == 35){    return "FFFFFFE9";    };
        if (index == 36){    return "FFFFFFE1";    };
        if (index == 37){    return "FFFFFFD9";    };
        if (index == 38){    return "FFFFFFD1";    };
        if (index == 39){    return "FFFFFFC9";    };
        if (index == 40){    return "FFFFFFC1";    };
        if (index == 41){    return "FFFFFFB9";    };
        if (index == 42){    return "FFFFFFB1";    };
        if (index == 43){    return "FFFFFFA9";    };
        if (index == 44){    return "FFFFFFA1";    };
        if (index == 45){    return "FFFFFF99";    };
        if (index == 46){    return "FFFFFF91";    };
        if (index == 47){    return "FFFFFF89";    };
        if (index == 48){    return "FFFFFF81";    };
        if (index == 49){    return "FFFFFF79";    };
        if (index == 50){    return "FFFFFF71";    };
        if (index == 51){    return "FFFFFF69";    };
        if (index == 52){    return "FFFFFF61";    };
        if (index == 53){    return "FFFFFF59";    };
        if (index == 54){    return "FFFFFF51";    };
        if (index == 55){    return "FFFFFF49";    };
        if (index == 56){    return "FFFFFF41";    };
        if (index == 57){    return "FFFFFF39";    };
        if (index == 58){    return "FFFFFF31";    };
        if (index == 59){    return "FFFFFF29";    };
        if (index == 60){    return "FFFFFF21";    };
        if (index == 61){    return "FFFFFF19";    };
        if (index == 62){    return "FFFFFF11";    };
        if (index == 63){    return "FFFFFF09";    };
        
        return "FFFFFF01";
    };
    
    INSTANCE DIA_Netbek_Alpha_Test (C_Info)
    {
        nr        = 2;
        npc        = NOV_1371_BaalNetbek;
        condition    = DIA_Netbek_Alpha_Test_Condition;
        information    = DIA_Netbek_Alpha_Test_Info;
        important    = FALSE;
        permanent    = TRUE;
        description    = "dummy";
    };
    
    FUNC INT DIA_Netbek_Alpha_Test_Condition ()
    {
        var string newDescription; newDescription = "c#";
    
        newDescription = ConcatStrings (newDescription, AlphaBlinkingHexColor ());
        newDescription = ConcatStrings (newDescription, " Transparence test");
        
        DIA_Netbek_Alpha_Test.description = newDescription;
    
        return TRUE;
    };
    
    FUNC VOID DIA_Netbek_Alpha_Test_Info ()
    {
    };
    
    FUNC STRING RandomLetter ()
    {
        var int randomizer;
        randomizer = Hlp_Random (101);
        
        if (randomizer == 00)    {    return "Ý";    };
        if (randomizer == 01)    {    return "Ţ";    };
        if (randomizer == 02)    {    return "ß";    };
        if (randomizer == 03)    {    return "ŕ";    };
        if (randomizer == 04)    {    return "á";    };
        if (randomizer == 05)    {    return "â";    };
        if (randomizer == 06)    {    return "ă";    };
        if (randomizer == 07)    {    return "ä";    };
        if (randomizer == 08)    {    return "ĺ";    };
        if (randomizer == 09)    {    return "ć";    };
        if (randomizer == 10)    {    return "ç";    };
        if (randomizer == 11)    {    return "č";    };
        if (randomizer == 12)    {    return "é";    };
        if (randomizer == 13)    {    return "ę";    };
        if (randomizer == 14)    {    return "ë";    };
        if (randomizer == 15)    {    return "ě";    };
        if (randomizer == 16)    {    return "í";    };
        if (randomizer == 17)    {    return "î";    };
        if (randomizer == 18)    {    return "ď";    };
        if (randomizer == 19)    {    return "đ";    };
        if (randomizer == 20)    {    return "ń";    };
        if (randomizer == 21)    {    return "ň";    };
        if (randomizer == 22)    {    return "ó";    };
        if (randomizer == 23)    {    return "ô";    };
        if (randomizer == 24)    {    return "ő";    };
        if (randomizer == 25)    {    return "ö";    };
        if (randomizer == 26)    {    return "÷";    };
        if (randomizer == 27)    {    return "ř";    };
        if (randomizer == 28)    {    return "ů";    };
        if (randomizer == 29)    {    return "ú";    };
        if (randomizer == 30)    {    return "ű";    };
        if (randomizer == 31)    {    return "ü";    };
        if (randomizer == 32)    {    return "ý";    };
        if (randomizer == 33)    {    return "ţ";    };
        if (randomizer == 34)    {    return "˙";    };
        
        if (randomizer == 35)    {    return "A";    };
        if (randomizer == 36)    {    return "B";    };
        if (randomizer == 37)    {    return "C";    };
        if (randomizer == 38)    {    return "D";    };
        if (randomizer == 39)    {    return "E";    };
        if (randomizer == 40)    {    return "F";    };
        if (randomizer == 41)    {    return "G";    };
        if (randomizer == 42)    {    return "H";    };
        if (randomizer == 43)    {    return "I";    };
        if (randomizer == 44)    {    return "J";    };
        if (randomizer == 45)    {    return "K";    };
        if (randomizer == 46)    {    return "L";    };
        if (randomizer == 47)    {    return "M";    };
        if (randomizer == 48)    {    return "N";    };
        if (randomizer == 49)    {    return "O";    };
        if (randomizer == 50)    {    return "P";    };
        if (randomizer == 51)    {    return "Q";    };
        if (randomizer == 52)    {    return "R";    };
        if (randomizer == 53)    {    return "S";    };
        if (randomizer == 54)    {    return "T";    };
        if (randomizer == 55)    {    return "U";    };
        if (randomizer == 56)    {    return "V";    };
        if (randomizer == 57)    {    return "W";    };
        if (randomizer == 58)    {    return "X";    };
        if (randomizer == 59)    {    return "Y";    };
        if (randomizer == 60)    {    return "Z";    };
        
        if (randomizer == 61)    {    return "a";    };
        if (randomizer == 62)    {    return "b";    };
        if (randomizer == 63)    {    return "c";    };
        if (randomizer == 64)    {    return "d";    };
        if (randomizer == 65)    {    return "e";    };
        if (randomizer == 66)    {    return "f";    };
        if (randomizer == 67)    {    return "g";    };
        if (randomizer == 68)    {    return "h";    };
        if (randomizer == 69)    {    return "i";    };
        if (randomizer == 70)    {    return "j";    };
        if (randomizer == 71)    {    return "k";    };
        if (randomizer == 72)    {    return "l";    };
        if (randomizer == 73)    {    return "m";    };
        if (randomizer == 74)    {    return "n";    };
        if (randomizer == 75)    {    return "o";    };
        if (randomizer == 76)    {    return "p";    };
        if (randomizer == 77)    {    return "q";    };
        if (randomizer == 78)    {    return "r";    };
        if (randomizer == 79)    {    return "s";    };
        if (randomizer == 80)    {    return "t";    };
        if (randomizer == 81)    {    return "u";    };
        if (randomizer == 82)    {    return "v";    };
        if (randomizer == 83)    {    return "w";    };
        if (randomizer == 84)    {    return "x";    };
        if (randomizer == 85)    {    return "y";    };
        if (randomizer == 86)    {    return "z";    };
        if (randomizer == 87)    {    return "0";    };
        if (randomizer == 88)    {    return "1";    };
        if (randomizer == 89)    {    return "2";    };
        if (randomizer == 90)    {    return "3";    };
        if (randomizer == 91)    {    return "4";    };
        if (randomizer == 92)    {    return "5";    };
        if (randomizer == 93)    {    return "6";    };
        if (randomizer == 94)    {    return "7";    };
        if (randomizer == 95)    {    return "8";    };
        if (randomizer == 96)    {    return "9";    };
    
    /*
        In this case we should not use '#' randomly assigned to letters as it can in a combination with color/font modifiers: f#, fs#, c#, cs# cause crash in hook _HOOK_INFORMATIONMANAGER_UPDATE
        if (randomizer == 97)    {    return "#";    };
    */    
        if (randomizer == 98)    {    return "$";    };
        if (randomizer == 99)    {    return "%";    };
        if (randomizer == 100)    {    return "&";    };
        
        return "$";
    };
    
    INSTANCE DIA_Netbek_Random_Text (C_Info)
    {
        nr        = 3;
        npc        = NOV_1371_BaalNetbek;
        condition    = DIA_Netbek_Random_Text_Condition;
        information    = DIA_Netbek_Random_Text_Info;
        important    = FALSE;
        permanent    = TRUE;
        description    = "dummy";
    };
    
    FUNC INT DIA_Netbek_Random_Text_Condition ()
    {
        //font_default
        //font_10_book
        //font_15_white
        //font_old_10_white
        //
        var string newDescription; newDescription = "f#font_old_10_white.tga ";
        
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, " Random ");
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, " letters ");
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, " test ");
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
        newDescription = ConcatStrings (newDescription, RandomLetter ());
    
        DIA_Netbek_Random_Text.description = newDescription;
        
        return TRUE;
    };
    
    FUNC VOID DIA_Netbek_Random_Text_Info ()
    {
    };

  10. Beiträge anzeigen #10 Zitieren
    now also in your universe  Avatar von Milky-Way
    Registriert seit
    Jun 2007
    Beiträge
    15.246
     
    Milky-Way ist offline
    Maybe it would alternatively be possible to switch the font to one with fixed width? The width of each letter is set in the font's .fnt file. I'm not sure whether you have access to those rendering details even through engine calls (you could maybe manually add the right amount of space after each letter, but some people use font patches, so for those it would be wrong if you can't determine the size dynamically.)

  11. Beiträge anzeigen #11 Zitieren
    Dea
    Registriert seit
    Jul 2007
    Beiträge
    10.447
     
    Lehona ist offline
    You can't (easily) make a font monospaced in Gothic, but you can change which font a zCViewText is displayed in, so you can supply your own font or choose one of the preexisting ones, if there is a monospaced one.

    LeGo also has a function to determine the width of a string so you could generate random strings until you find one that has a similar length (which may take a long time depending on how similar it has to be).

    Edit: Maybe it looks a lot better if you only change one letter at a time, going from left to right. That would make it look a lot less busy.

  12. Beiträge anzeigen #12 Zitieren
    Local Hero
    Registriert seit
    Feb 2017
    Beiträge
    270
     
    F a w k e s ist offline
    Hello Milky-Way, Lehona,
    Thank you for your inputs! This got me thinking - and one solution is to use Print_GetStringWidth and loop through letters to figure out what width is most used one. This way code should work even in case font_default.tga would be changed by some patch. Seems like in vanilla G1 there is 26 letters out of 100 I was searching within with same size of 9 pixels ('a' for example). I was hoping for more of these - randomly generated text is not as insane as I would hope for, but this will have to do for now. Thank you!

    [Video]

    Updated function RandomLetter:
    Code:
    FUNC STRING RandomLetter ()
    {
        const int maxLetters = 99;
        var int letterWidth[100];
    
        const int once = 0;
        
        var int i;
        var int j;
        
        var int p1;    //MEM_StackPos variable for loop 1
        var int p2;    //MEM_StackPos variable for loop 2
        
        //Get width of each letter
        if (!once) {
            letterWidth[00] = Print_GetStringWidth (" ", "font_default.tga");
            letterWidth[00] = Print_GetStringWidth ("Ý", "font_default.tga");
            letterWidth[01] = Print_GetStringWidth ("Ţ", "font_default.tga");
            letterWidth[02] = Print_GetStringWidth ("ß", "font_default.tga");
            letterWidth[03] = Print_GetStringWidth ("ŕ", "font_default.tga");
            letterWidth[04] = Print_GetStringWidth ("á", "font_default.tga");
            letterWidth[05] = Print_GetStringWidth ("â", "font_default.tga");
            letterWidth[06] = Print_GetStringWidth ("ă", "font_default.tga");
            letterWidth[07] = Print_GetStringWidth ("ä", "font_default.tga");
            letterWidth[08] = Print_GetStringWidth ("ĺ", "font_default.tga");
            letterWidth[09] = Print_GetStringWidth ("ć", "font_default.tga");
            letterWidth[10] = Print_GetStringWidth ("ç", "font_default.tga");
            letterWidth[11] = Print_GetStringWidth ("č", "font_default.tga");
            letterWidth[12] = Print_GetStringWidth ("é", "font_default.tga");
            letterWidth[13] = Print_GetStringWidth ("ę", "font_default.tga");
            letterWidth[14] = Print_GetStringWidth ("ë", "font_default.tga");
            letterWidth[15] = Print_GetStringWidth ("ě", "font_default.tga");
            letterWidth[16] = Print_GetStringWidth ("í", "font_default.tga");
            letterWidth[17] = Print_GetStringWidth ("î", "font_default.tga");
            letterWidth[18] = Print_GetStringWidth ("ď", "font_default.tga");
            letterWidth[19] = Print_GetStringWidth ("đ", "font_default.tga");
            letterWidth[20] = Print_GetStringWidth ("ń", "font_default.tga");
            letterWidth[21] = Print_GetStringWidth ("ň", "font_default.tga");
            letterWidth[22] = Print_GetStringWidth ("ó", "font_default.tga");
            letterWidth[23] = Print_GetStringWidth ("ô", "font_default.tga");
            letterWidth[24] = Print_GetStringWidth ("ő", "font_default.tga");
            letterWidth[25] = Print_GetStringWidth ("ö", "font_default.tga");
            letterWidth[26] = Print_GetStringWidth ("÷", "font_default.tga");
            letterWidth[27] = Print_GetStringWidth ("ř", "font_default.tga");
            letterWidth[28] = Print_GetStringWidth ("ů", "font_default.tga");
            letterWidth[29] = Print_GetStringWidth ("ú", "font_default.tga");
            letterWidth[30] = Print_GetStringWidth ("ű", "font_default.tga");
            letterWidth[31] = Print_GetStringWidth ("ü", "font_default.tga");
            letterWidth[32] = Print_GetStringWidth ("ý", "font_default.tga");
            letterWidth[33] = Print_GetStringWidth ("ţ", "font_default.tga");
            letterWidth[34] = Print_GetStringWidth ("˙", "font_default.tga");
    
            letterWidth[35] = Print_GetStringWidth ("A", "font_default.tga");
            letterWidth[36] = Print_GetStringWidth ("B", "font_default.tga");
            letterWidth[37] = Print_GetStringWidth ("C", "font_default.tga");
            letterWidth[38] = Print_GetStringWidth ("D", "font_default.tga");
            letterWidth[39] = Print_GetStringWidth ("E", "font_default.tga");
            letterWidth[40] = Print_GetStringWidth ("F", "font_default.tga");
            letterWidth[41] = Print_GetStringWidth ("G", "font_default.tga");
            letterWidth[42] = Print_GetStringWidth ("H", "font_default.tga");
            letterWidth[43] = Print_GetStringWidth ("I", "font_default.tga");
            letterWidth[44] = Print_GetStringWidth ("J", "font_default.tga");
            letterWidth[45] = Print_GetStringWidth ("K", "font_default.tga");
            letterWidth[46] = Print_GetStringWidth ("L", "font_default.tga");
            letterWidth[47] = Print_GetStringWidth ("M", "font_default.tga");
            letterWidth[48] = Print_GetStringWidth ("N", "font_default.tga");
            letterWidth[49] = Print_GetStringWidth ("O", "font_default.tga");
            letterWidth[50] = Print_GetStringWidth ("P", "font_default.tga");
            letterWidth[51] = Print_GetStringWidth ("Q", "font_default.tga");
            letterWidth[52] = Print_GetStringWidth ("R", "font_default.tga");
            letterWidth[53] = Print_GetStringWidth ("S", "font_default.tga");
            letterWidth[54] = Print_GetStringWidth ("T", "font_default.tga");
            letterWidth[55] = Print_GetStringWidth ("U", "font_default.tga");
            letterWidth[56] = Print_GetStringWidth ("V", "font_default.tga");
            letterWidth[57] = Print_GetStringWidth ("W", "font_default.tga");
            letterWidth[58] = Print_GetStringWidth ("X", "font_default.tga");
            letterWidth[59] = Print_GetStringWidth ("Y", "font_default.tga");
            letterWidth[60] = Print_GetStringWidth ("Z", "font_default.tga");
    
            letterWidth[61] = Print_GetStringWidth ("a", "font_default.tga");
            letterWidth[62] = Print_GetStringWidth ("b", "font_default.tga");
            letterWidth[63] = Print_GetStringWidth ("c", "font_default.tga");
            letterWidth[64] = Print_GetStringWidth ("d", "font_default.tga");
            letterWidth[65] = Print_GetStringWidth ("e", "font_default.tga");
            letterWidth[66] = Print_GetStringWidth ("f", "font_default.tga");
            letterWidth[67] = Print_GetStringWidth ("g", "font_default.tga");
            letterWidth[68] = Print_GetStringWidth ("h", "font_default.tga");
            letterWidth[69] = Print_GetStringWidth ("i", "font_default.tga");
            letterWidth[70] = Print_GetStringWidth ("j", "font_default.tga");
            letterWidth[71] = Print_GetStringWidth ("k", "font_default.tga");
            letterWidth[72] = Print_GetStringWidth ("l", "font_default.tga");
            letterWidth[73] = Print_GetStringWidth ("m", "font_default.tga");
            letterWidth[74] = Print_GetStringWidth ("n", "font_default.tga");
            letterWidth[75] = Print_GetStringWidth ("o", "font_default.tga");
            letterWidth[76] = Print_GetStringWidth ("p", "font_default.tga");
            letterWidth[77] = Print_GetStringWidth ("q", "font_default.tga");
            letterWidth[78] = Print_GetStringWidth ("r", "font_default.tga");
            letterWidth[79] = Print_GetStringWidth ("s", "font_default.tga");
            letterWidth[80] = Print_GetStringWidth ("t", "font_default.tga");
            letterWidth[81] = Print_GetStringWidth ("u", "font_default.tga");
            letterWidth[82] = Print_GetStringWidth ("v", "font_default.tga");
            letterWidth[83] = Print_GetStringWidth ("w", "font_default.tga");
            letterWidth[84] = Print_GetStringWidth ("x", "font_default.tga");
            letterWidth[85] = Print_GetStringWidth ("y", "font_default.tga");
            letterWidth[86] = Print_GetStringWidth ("z", "font_default.tga");
            letterWidth[87] = Print_GetStringWidth ("0", "font_default.tga");
            letterWidth[88] = Print_GetStringWidth ("1", "font_default.tga");
            letterWidth[89] = Print_GetStringWidth ("2", "font_default.tga");
            letterWidth[90] = Print_GetStringWidth ("3", "font_default.tga");
            letterWidth[91] = Print_GetStringWidth ("4", "font_default.tga");
            letterWidth[92] = Print_GetStringWidth ("5", "font_default.tga");
            letterWidth[93] = Print_GetStringWidth ("6", "font_default.tga");
            letterWidth[94] = Print_GetStringWidth ("7", "font_default.tga");
            letterWidth[95] = Print_GetStringWidth ("8", "font_default.tga");
            letterWidth[96] = Print_GetStringWidth ("9", "font_default.tga");
            letterWidth[96] = Print_GetStringWidth ("$", "font_default.tga");
            letterWidth[97] = Print_GetStringWidth ("%", "font_default.tga");
            letterWidth[99] = Print_GetStringWidth ("&", "font_default.tga");
            
            var int count;
            var int maxCount; maxCount = 0;
            var int widthMax; widthMax = -1;
            
            //1st loop through each letter
            i = 0;
            p1 = MEM_StackPos.position;
    
                j = i;
                count = 0;
                
                //2nd loop - count how many letters have same width
                p2 = MEM_StackPos.position;
                
                if (MEM_ReadIntArray (_@ (letterWidth), i) == MEM_ReadIntArray (_@ (letterWidth), j)) {
                    count += 1;
                };
                
                //remember width of this one, this is most common width
                if (count > maxCount) {
                    maxCount = count;
                    widthMax = MEM_ReadIntArray (_@ (letterWidth), i);
                };
            
                j += 1;
                if (j < maxLetters) {
                    MEM_StackPos.position = p2;
                };
                
                i += 1;
                
            if (i < maxLetters) {
                MEM_StackPos.position = p1;
            };
            
            once = 1;
        };
        
        var int randomizer;
        randomizer = Hlp_Random (maxLetters + 1);
    
        p1 = MEM_StackPos.position;
        
        if (widthMax == MEM_ReadIntArray(_@ (letterWidth), randomizer)) {
            if (randomizer == 00)    {    return "Ý";    };
            if (randomizer == 01)    {    return "Ţ";    };
            if (randomizer == 02)    {    return "ß";    };
            if (randomizer == 03)    {    return "ŕ";    };
            if (randomizer == 04)    {    return "á";    };
            if (randomizer == 05)    {    return "â";    };
            if (randomizer == 06)    {    return "ă";    };
            if (randomizer == 07)    {    return "ä";    };
            if (randomizer == 08)    {    return "ĺ";    };
            if (randomizer == 09)    {    return "ć";    };
            if (randomizer == 10)    {    return "ç";    };
            if (randomizer == 11)    {    return "č";    };
            if (randomizer == 12)    {    return "é";    };
            if (randomizer == 13)    {    return "ę";    };
            if (randomizer == 14)    {    return "ë";    };
            if (randomizer == 15)    {    return "ě";    };
            if (randomizer == 16)    {    return "í";    };
            if (randomizer == 17)    {    return "î";    };
            if (randomizer == 18)    {    return "ď";    };
            if (randomizer == 19)    {    return "đ";    };
            if (randomizer == 20)    {    return "ń";    };
            if (randomizer == 21)    {    return "ň";    };
            if (randomizer == 22)    {    return "ó";    };
            if (randomizer == 23)    {    return "ô";    };
            if (randomizer == 24)    {    return "ő";    };
            if (randomizer == 25)    {    return "ö";    };
            if (randomizer == 26)    {    return "÷";    };
            if (randomizer == 27)    {    return "ř";    };
            if (randomizer == 28)    {    return "ů";    };
            if (randomizer == 29)    {    return "ú";    };
            if (randomizer == 30)    {    return "ű";    };
            if (randomizer == 31)    {    return "ü";    };
            if (randomizer == 32)    {    return "ý";    };
            if (randomizer == 33)    {    return "ţ";    };
            if (randomizer == 34)    {    return "˙";    };
    
            if (randomizer == 35)    {    return "A";    };
            if (randomizer == 36)    {    return "B";    };
            if (randomizer == 37)    {    return "C";    };
            if (randomizer == 38)    {    return "D";    };
            if (randomizer == 39)    {    return "E";    };
            if (randomizer == 40)    {    return "F";    };
            if (randomizer == 41)    {    return "G";    };
            if (randomizer == 42)    {    return "H";    };
            if (randomizer == 43)    {    return "I";    };
            if (randomizer == 44)    {    return "J";    };
            if (randomizer == 45)    {    return "K";    };
            if (randomizer == 46)    {    return "L";    };
            if (randomizer == 47)    {    return "M";    };
            if (randomizer == 48)    {    return "N";    };
            if (randomizer == 49)    {    return "O";    };
            if (randomizer == 50)    {    return "P";    };
            if (randomizer == 51)    {    return "Q";    };
            if (randomizer == 52)    {    return "R";    };
            if (randomizer == 53)    {    return "S";    };
            if (randomizer == 54)    {    return "T";    };
            if (randomizer == 55)    {    return "U";    };
            if (randomizer == 56)    {    return "V";    };
            if (randomizer == 57)    {    return "W";    };
            if (randomizer == 58)    {    return "X";    };
            if (randomizer == 59)    {    return "Y";    };
            if (randomizer == 60)    {    return "Z";    };
    
            if (randomizer == 61)    {    return "a";    };
            if (randomizer == 62)    {    return "b";    };
            if (randomizer == 63)    {    return "c";    };
            if (randomizer == 64)    {    return "d";    };
            if (randomizer == 65)    {    return "e";    };
            if (randomizer == 66)    {    return "f";    };
            if (randomizer == 67)    {    return "g";    };
            if (randomizer == 68)    {    return "h";    };
            if (randomizer == 69)    {    return "i";    };
            if (randomizer == 70)    {    return "j";    };
            if (randomizer == 71)    {    return "k";    };
            if (randomizer == 72)    {    return "l";    };
            if (randomizer == 73)    {    return "m";    };
            if (randomizer == 74)    {    return "n";    };
            if (randomizer == 75)    {    return "o";    };
            if (randomizer == 76)    {    return "p";    };
            if (randomizer == 77)    {    return "q";    };
            if (randomizer == 78)    {    return "r";    };
            if (randomizer == 79)    {    return "s";    };
            if (randomizer == 80)    {    return "t";    };
            if (randomizer == 81)    {    return "u";    };
            if (randomizer == 82)    {    return "v";    };
            if (randomizer == 83)    {    return "w";    };
            if (randomizer == 84)    {    return "x";    };
            if (randomizer == 85)    {    return "y";    };
            if (randomizer == 86)    {    return "z";    };
            if (randomizer == 87)    {    return "0";    };
            if (randomizer == 88)    {    return "1";    };
            if (randomizer == 89)    {    return "2";    };
            if (randomizer == 90)    {    return "3";    };
            if (randomizer == 91)    {    return "4";    };
            if (randomizer == 92)    {    return "5";    };
            if (randomizer == 93)    {    return "6";    };
            if (randomizer == 94)    {    return "7";    };
            if (randomizer == 95)    {    return "8";    };
            if (randomizer == 96)    {    return "9";    };
            if (randomizer == 96)    {    return "$";    };
            if (randomizer == 97)    {    return "%";    };
            if (randomizer == 99)    {    return "&";    };
            
            /*
            In this case we should not use '#' randomly assigned to letters as it can in a combination with color/font modifiers: f#, fs#, c#, cs# cause crash in hook _HOOK_INFORMATIONMANAGER_UPDATE
            if (randomizer == 97)    {    return "#";    };
            */    
        };
        
        randomizer = randomizer + 1;
        if (randomizer > maxLetters) {
            randomizer = 0;
        };
        
        MEM_StackPos.position = p1;
        
        return "Impossible error!";
    };

  13. Beiträge anzeigen #13 Zitieren
    Dea
    Registriert seit
    Jul 2007
    Beiträge
    10.447
     
    Lehona ist offline
    I think if you slow it down a lot - e.g. only change a few letters at a time and at a far slower frequency it might look even better. Currently it reminds me of a slot machine due to the speed.

  14. Beiträge anzeigen #14 Zitieren
    Local Hero
    Registriert seit
    Feb 2017
    Beiträge
    270
     
    F a w k e s ist offline

    G1/G2 Dialog Input field

    Hello folks,
    Bisasam's recent topic about Input fields inspired me to revisit script for dialog font & color change. I have implemented now new feature:
    • by adding new dialog description modifier 'a@' you can now use dialog option as an Input field and you can enter free text into it.

    [Video]

    This is how you can use it ingame - usage is very simple:
    Code:
    INSTANCE DIA_Diego_Answer1 (C_Info) {
           npc             = PC_Thief;
           nr              = 900;
           condition       = DIA_Diego_Answer1_Condition;
           information     = DIA_Diego_Answer1_Info;
           permanent       = TRUE;
           important       = FALSE;
           //Default color 00CC66, selected color 66FFB2, @a modifier enables this dialog option as an Input field
           description     = "h@00CC66 hs@66FFB2 a@ What secret password will allow you to visit Water Mages in New Camp ?";
    };
    
    FUNC INT DIA_Diego_Answer1_Condition () {
           return TRUE;
    };
    
    FUNC VOID DIA_Diego_Answer1_Info () {
           if (Hlp_StrCmp (InfoManagerAnswer, "TETRIANDOCH")) {
                  PrintScreen ("Yes that is correct!", -1, -1, "font_old_10_white.tga", 3);
           } else {
                  PrintScreen ("No that is wrong!", -1, -1, "font_old_10_white.tga", 3);
           };
    };
    
    INSTANCE DIA_Diego_Answer2 (C_Info) {
           npc             = PC_Thief;
           nr              = 901;
           condition       = DIA_Diego_Answer2_Condition;
           information     = DIA_Diego_Answer2_Info;
           permanent       = TRUE;
           important       = FALSE;
           //@a modifier enables this dialog option as an Input field
           description     = "a@ Who is the pirate leader in G2A?";
    };
    
    FUNC INT DIA_Diego_Answer2_Condition () {
           return TRUE;
    };
    
    FUNC VOID DIA_Diego_Answer2_Info () {
           if (Hlp_StrCmp (InfoManagerAnswer, "GREG")) {
                  PrintScreen ("Yes that is correct!", -1, -1, "font_old_10_white.tga", 3);
           } else {
                  PrintScreen ("No that is wrong!", -1, -1, "font_old_10_white.tga", 3);
           };
    };
    
    INSTANCE DIA_Diego_Answer3 (C_Info) {
           npc             = PC_Thief;
           nr              = 902;
           condition       = DIA_Diego_Answer3_Condition;
           information     = DIA_Diego_Answer3_Info;
           permanent       = TRUE;
           important       = FALSE;
           description     = "Choice test";
    };
    
    FUNC INT DIA_Diego_Answer3_Condition () {
           return TRUE;
    };
    
    FUNC VOID DIA_Diego_Answer3_Info () {
           Info_ClearChoices (DIA_Diego_Answer3);
    
           //@a modifier enables this dialog choice as an Input field
           Info_AddChoice (DIA_Diego_Answer3, "a@ What secret password will allow you to visit Water Mages in New Camp ?", DIA_Diego_Validate_Answer3);
    };
    
    FUNC VOID DIA_Diego_Validate_Answer3 () {
           Info_ClearChoices (DIA_Diego_Answer3);
           if (Hlp_StrCmp (InfoManagerAnswer, "TETRIANDOCH")) {
                  PrintScreen ("Yes that is correct!", -1, -1, "font_old_10_white.tga", 3);
           } else {
                  PrintScreen ("No that is wrong!", -1, -1, "font_old_10_white.tga", 3);
           };
    };

    Script in first post updated.

    Input field uses US english keyboard Layout:
    KEY_1 in combination with shift will give you exclamation mark '!'
    KEY_9 in combination with shift will give you left bracket '(' ...

    Important note --> if you were using older version, I have changed previous modifiers now, you will have to update old modifiers in your scripts:
    from 'c#' to 'h@'
    from 'cs#' to 'hs@'
    from 'f#' to 'f@'
    from 'fs#' to 'fs@'

    Apologies for any inconvenience. I have done this, because I wanted to remain consistent. In another thread I have implemented similar notation changing dialog colors by using modifier h@.
    https://forum.worldofplayers.de/foru...1#post26255423
    (I was not able to use # in dialogs, that's why I used @)

    Let me know in case you see any issues.

  15. Beiträge anzeigen #15 Zitieren
    Local Hero
    Registriert seit
    Feb 2017
    Beiträge
    270
     
    F a w k e s ist offline

    G1/G2 Dialog Spinner

    Hello folks,
    Today I have added new feature 'Spinner' for dialogs. Spinner allows you to use Left / Right arrow key on a dialog option to decrease / increase numerical value of global variable InfoManagerSpinnerValue. If used properly this can improve both player's and modder's experience significantly.

    Let's have a look for example on Meat cooking. With this feature as a modder you don't have to add any Info_AddChoice options into your dialog, as a player you don't have to go through any dialog choices.

    You can just simply use navigation keys to countol amount of items:
    Left arrow key: InfoManagerSpinnerValue = InfoManagerSpinnerValue - 1
    Right arrow key: InfoManagerSpinnerValue = InfoManagerSpinnerValue + 1
    Page Up key: InfoManagerSpinnerValue = InfoManagerSpinnerValue - InfoManagerSpinnerPageSize
    Page Down key: InfoManagerSpinnerValue = InfoManagerSpinnerValue + InfoManagerSpinnerPageSize
    Home key: InfoManagerSpinnerValue = InfoManagerSpinnerValueMin
    End key: InfoManagerSpinnerValue = InfoManagerSpinnerValueMax

    Check this video out to see how this feature can be used with both FaceHelper and Meat cooking:

    [Video]

    Unlike with Input field I have implemented previously - here usage is much more complex. But it is worth it!

    Once again, you have to add modifier to your dialog description that enables this feature. Spinner modifier has to be in format 's@spinnerID' where 'spinnerID' is in text format (cannot contain spaces) and should be unique for each spinner in one dialog window.
    SpinnerID is required because you can have multiple spinners in your dialogs. What is displayed in a dialog description is completely maintained from condition function --> see below examples.

    Script in first post updated.

    Both examples demonstrated in above video are here, you can use them as templates when creating your own spinners:

    1. Meat cooking
    Code:
    INSTANCE PC_Pan_Cook_Meat (C_Info) {
           nr        = 1;
           condition    = PC_Pan_Cook_Meat_Condition;
           information    = PC_Pan_Cook_Meat_Info;
           permanent    = TRUE;
           description    = "dummy"; //Description is updated in PC_Pan_Cook_Meat_Condition
    };
    
    FUNC INT PC_Pan_Cook_Meat_Condition () {
           if (PLAYER_MOBSI_PRODUCTION == MOBSI_DIALOG_PAN) {
                  var string lastSpinnerID;    //Actually global variable! ;-) Will help us to recognize whether current spinner is this one, as we will store in it last spinner ID
                  var int selectedMeat;        //Another global variable - number of items, which user selected
            
                  var int total; total = NPC_HasItems (self, ItFoMuttonRaw);
    
                  if (selectedMeat == 0) { selectedMeat = 1; }; //Default initial value
    
                  //Check currently selected spinned ID --> is it this one?
                  if (Hlp_StrCmp (InfoManagerSpinnerID, "CookMeat")) {
                         //Setup spinner if spinner ID has changed
                         if (!Hlp_StrCmp (InfoManagerSpinnerID, lastSpinnerID)) {
                                //Restore previous value
                                InfoManagerSpinnerValue = selectedMeat;
                         };
    
                         //Page Up/Down quantity
                         InfoManagerSpinnerPageSize = 5;
                
                         //Min/Max value (Home/End keys)
                         InfoManagerSpinnerValueMin = 1;
                         InfoManagerSpinnerValueMax = total;
    
                         //Update number which is shown in description (in case it was changed by _HOOK_VIEWDIALOGCHOICE_HANDLEEVENT
                         selectedMeat = InfoManagerSpinnerValue;
                  };
    
                  lastSpinnerID = InfoManagerSpinnerID; //Remember last active spinner ID
    
                  var string newDescription;
    
                  //Spinner ID 'CookMeat'
                  newDescription = "s@CookMeat Cook some meat: ";
    
                  newDescription = ConcatStrings (newDescription, IntToString (selectedMeat));
                  newDescription = ConcatStrings (newDescription, " / ");
                  newDescription = ConcatStrings (newDescription, IntToString (total));
    
                  //Update description
                  PC_Pan_Cook_Meat.description = newDescription;
                  return TRUE;
           };
    
           return FALSE;
    };
    
    FUNC VOID PC_Pan_Cook_Meat_Info () {
           //If we don't have any meat ... don't cook any :)
           if (!NPC_HasItems (self, ItFoMuttonRaw)) { return; };
    
           //This should not happen - but you never know!
           if (InfoManagerSpinnerValue < 1) { return; };
    
           //This should not happen either! but just in case
           if (InfoManagerSpinnerValue > (NPC_HasItems (self, ItFoMuttonRaw))) {
                  InfoManagerSpinnerValue = NPC_HasItems (self, ItFoMuttonRaw);
           };
    
           NPC_RemoveInvItems (self, ItFoMuttonRaw, InfoManagerSpinnerValue);
           CreateInvItems (self, ItFoMutton, InfoManagerSpinnerValue);
        
           B_GiveXP (XP_Bonus_Cooking * InfoManagerSpinnerValue);
        
           //Reset value for next time
           InfoManagerSpinnerValue = 1;
    };
    
    INSTANCE PC_Pan_Cook_Meat_Exit (C_Info) {
           nr        = 999;
           condition    = PC_Pan_Cook_Meat_Exit_Condition;
           information    = PC_Pan_Cook_Meat_Exit_Info;
           permanent    = TRUE;
           description    = "END";
    };
    
    FUNC INT PC_Pan_Cook_Meat_Exit_Condition ()
    {
           if (PLAYER_MOBSI_PRODUCTION == MOBSI_DIALOG_PAN) {
                  return TRUE;
           };
    
           return FALSE;
    };
    
    FUNC VOID PC_Pan_Cook_Meat_Exit_Info () {
           if (PLAYER_MOBSI_PRODUCTION != MOBSI_DIALOG_NONE) {
                  PLAYER_MOBSI_PRODUCTION = MOBSI_DIALOG_NONE;
    
                  hero.aivar [AIV_INVINCIBLE] = FALSE;
                  AI_StopProcessInfos (hero);
           };
    };
    
    FUNC VOID Pan_Dialog_S1 ()
    {
           var C_NPC her; her = Hlp_GetNpc (PC_Hero); 
    
           if (Hlp_GetInstanceID (self) == Hlp_GetInstanceID (her)) {
                  self.aivar [AIV_INVINCIBLE] = TRUE; 
                  PLAYER_MOBSI_PRODUCTION = MOBSI_DIALOG_PAN;
    
                  //Default value
                  InfoManagerSpinnerValue = 1;
            
                  PC_Pan_Cook_Meat.npc = Hlp_GetInstanceID (self);
                  PC_Pan_Cook_Meat_Exit.npc = Hlp_GetInstanceID (self);
    
                  AI_ProcessInfos (self);
           };
    };

    2. G1 FaceHelper
    (this will not work if you just copy-paste it, I am using some functions in code, which are not defined in this post)
    Code:
    //                body mesh,        bdytex            skin,            head mesh,        headtex,        teethtex,        ruestung    
    //Mdl_SetVisualBody    (self,    "hum_body_Naked0",    FaceHelper_BodyTex,     FaceHelper_Skin,    FaceHelper_HeadMesh,    FaceHelper_HeadTex,    FaceHelper_TeethTex,    itemInstance);
    
    const int FaceHelper_BodyTex_Max        = 4; //0 - 4 | 5 - 12 babes
    const int FaceHelper_Skin_Max            = 3; //0 - 3
    const int FaceHelper_HeadTex_Max        = 117; //0 - 117
    const int FaceHelper_HeadMesh_Max        = 6; //0 - 6
    const int FaceHelper_TeethTex_Max        = 3; //0 - 3
    const int FaceHelper_Armor_Max            = 36; //-1 - 36
    
    var int FaceHelper_BodyTex;
    var int FaceHelper_Skin;
    
    var int FaceHelper_HeadMesh;
    var string FaceHelper_HeadMesh_Name;
    
    var int FaceHelper_HeadTex;
    
    var int FaceHelper_TeethTex;
    
    var int FaceHelper_Armor;
    var string FaceHelper_Armor_Name;
    var int FaceHelper_Armor_Instance;
    
    FUNC VOID ZS_FH_Hangaround () {
           NPC_PercEnable (self, PERC_ASSESSTALK, FH_Dialogs);
    };
    
    FUNC VOID ZS_FH_Hangaround_Loop () {};
    
    FUNC VOID ZS_FH_Hangaround_End () {};
    
    INSTANCE FH (Npc_Default) {
           Name[0]        = "Face Helper";
           NPCType        = NPCType_Main;
           Guild        = GIL_NONE;
    
           Level        = 10;
           Voice        = 15;
           ID        = 0;
    
           senses                 = SENSE_HEAR | SENSE_SEE | SENSE_SMELL;
           senses_range             = 3000;
    
           //Default values
           FaceHelper_BodyTex = 3;
           FaceHelper_Skin = 1;
           FaceHelper_HeadMesh_Name = "HUM_HEAD_THIEF";
           FaceHelper_HeadMesh = 2;
           FaceHelper_HeadTex = 67;
        
           FaceHelper_Armor = -1;
           FaceHelper_Armor_Name = "NO ARMOR";
           FaceHelper_Armor_Instance = -1;
    
           Mdl_SetVisual (self, "HUMANS.MDS");
           Mdl_SetVisualBody (self, "hum_body_Naked0", FaceHelper_BodyTex, FaceHelper_Skin, FaceHelper_HeadMesh_Name, FaceHelper_HeadTex, 0, -1);
    
           //Create armors in inventory
           CreateInvItem (self, VLK_ARMOR_L);
           CreateInvItem (self, VLK_ARMOR_M);
           CreateInvItem (self, SFB_ARMOR_L);
           CreateInvItem (self, TPL_ARMOR_L);
           CreateInvItem (self, TPL_ARMOR_M);
           CreateInvItem (self, TPL_ARMOR_H);
           CreateInvItem (self, STT_ARMOR_M);
           CreateInvItem (self, STT_ARMOR_H);
           CreateInvItem (self, GRD_ARMOR_L);
           CreateInvItem (self, GRD_ARMOR_M);
           CreateInvItem (self, GRD_ARMOR_H);
           CreateInvItem (self, KDF_ARMOR_L);
           CreateInvItem (self, KDF_ARMOR_H);
           CreateInvItem (self, KDW_ARMOR_L);
           CreateInvItem (self, KDW_ARMOR_H);
           CreateInvItem (self, GUR_ARMOR_M);
           CreateInvItem (self, GUR_ARMOR_H);
           CreateInvItem (self, ORG_ARMOR_L);
           CreateInvItem (self, ORG_ARMOR_M);
           CreateInvItem (self, ORG_ARMOR_H);
           CreateInvItem (self, SLD_ARMOR_L);
           CreateInvItem (self, SLD_ARMOR_M);
           CreateInvItem (self, SLD_ARMOR_H);
           CreateInvItem (self, NOV_ARMOR_L);
           CreateInvItem (self, NOV_ARMOR_M);
           CreateInvItem (self, NOV_ARMOR_H);
           CreateInvItem (self, CRW_ARMOR_H);
           CreateInvItem (self, DMB_ARMOR_M);
           CreateInvItem (self, ORE_ARMOR_M);
           CreateInvItem (self, ORE_ARMOR_H);
           CreateInvItem (self, EBR_ARMOR_M);
           CreateInvItem (self, EBR_ARMOR_H);
           CreateInvItem (self, EBR_ARMOR_H2);
           CreateInvItem (self, GRD_ARMOR_I);
           CreateInvItem (self, PIRATE_ARMOR_M);
           CreateInvItem (self, DEMENTOR_ARMOR);
           CreateInvItem (self, LAW_ARMOR);
           
           start_aistate = ZS_FH_Hangaround;
    };
    
    FUNC VOID FH_ChangeVisual ()
    {
           var C_NPC npc; npc = Hlp_GetNPC (FH);
    
           NPC_UnEquip_invCategory (npc, INV_ARMOR);
    
           //                            body mesh,              bdytex                     skin,                     head mesh,              headtex,              teethtex,              ruestung       
           Mdl_SetVisualBody       (npc,       "hum_body_Naked0",       FaceHelper_BodyTex,        FaceHelper_Skin,       FaceHelper_HeadMesh_Name,       FaceHelper_HeadTex,       FaceHelper_TeethTex,       -1);
           
           if (FaceHelper_Armor_Instance != -1) {
                  AI_EquipArmor (npc, FaceHelper_Armor_Instance);
           };
    };
    
    INSTANCE FaceHelper_Exit (C_Info)
    {
           nr              = 999;
           condition       = FaceHelper_Exit_Condition;
           information       = FaceHelper_Exit_Info;
           important       = FALSE;
           permanent       = TRUE;
           description       = DIALOG_ENDE;
    };
    
    FUNC INT FaceHelper_Exit_Condition () {
           if (PLAYER_MOBSI_PRODUCTION == MOBSI_FACEHELPER) {
                  return TRUE;
           };
    
           return FALSE;
    };
    
    FUNC VOID FaceHelper_Exit_Info () {
           PLAYER_MOBSI_PRODUCTION = MOBSI_NONE;
           AI_StopProcessInfos (self);
    };
    
    INSTANCE FaceHelper_HeadMesh_Change (C_Info)
    {
           nr              = 5;
           condition       = FaceHelper_HeadMesh_Change_Condition;
           information       = FaceHelper_Exit_Info ;
           important       = FALSE;
           permanent       = TRUE;
           description       = "dummy";
    };
    
    FUNC INT FaceHelper_HeadMesh_Change_Condition () {
           if (PLAYER_MOBSI_PRODUCTION == MOBSI_FACEHELPER) {
                  //Figure out if we need to reset InfoManagerSpinnerValue value
                  var string lastSpinnerID; //Actually global variable! ;-)
    
                  if (Hlp_StrCmp (InfoManagerSpinnerID, "1")) {
                         //Setup spinner if spinner ID has changed
                         if (!Hlp_StrCmp (InfoManagerSpinnerID, lastSpinnerID)) {
                                InfoManagerSpinnerValue = FaceHelper_HeadMesh;
                         };
    
                         InfoManagerSpinnerValueMin = 0;
                         InfoManagerSpinnerValueMax = FaceHelper_HeadMesh_Max;
                         
                         //Update Face Helper visual if spinner changed
                         if (FaceHelper_HeadMesh != InfoManagerSpinnerValue) {
                                FaceHelper_HeadMesh = InfoManagerSpinnerValue;
    
                                if (FaceHelper_HeadMesh == 0) { FaceHelper_HeadMesh_Name = "HUM_HEAD_PSIONIC"; } else
                                if (FaceHelper_HeadMesh == 1) { FaceHelper_HeadMesh_Name = "HUM_HEAD_FIGHTER"; } else
                                if (FaceHelper_HeadMesh == 2) { FaceHelper_HeadMesh_Name = "HUM_HEAD_THIEF"; } else
                                if (FaceHelper_HeadMesh == 3) { FaceHelper_HeadMesh_Name = "HUM_HEAD_STD_PONY"; } else
                                if (FaceHelper_HeadMesh == 4) { FaceHelper_HeadMesh_Name = "HUM_HEAD_PONY"; } else
                                if (FaceHelper_HeadMesh == 5) { FaceHelper_HeadMesh_Name = "HUM_HEAD_FATBALD"; } else
                                if (FaceHelper_HeadMesh == 6) { FaceHelper_HeadMesh_Name = "HUM_HEAD_BALD"; };
    
                                FH_ChangeVisual ();
                         };
                  };
    
                  lastSpinnerID = InfoManagerSpinnerID;
    
                  var string newDescription;
    
                  //Spinner ID 1
                  newDescription = "s@1 <-- ";
    
                  newDescription = ConcatStrings (newDescription, FaceHelper_HeadMesh_Name);
                  newDescription = ConcatStrings (newDescription, " --> ");
                  newDescription = ConcatStrings (newDescription, IntToString (FaceHelper_HeadMesh));
                  newDescription = ConcatStrings (newDescription, " / ");
                  newDescription = ConcatStrings (newDescription, IntToString (FaceHelper_HeadMesh_Max));
    
                  //Update description
                  FaceHelper_HeadMesh_Change.description = newDescription;
                  
                  return TRUE;
           };
    
           return FALSE;
    };
    
    INSTANCE FaceHelper_BodyTex_Change (C_Info) {
           nr              = 10;
           condition       = FaceHelper_BodyTex_Change_Condition;
           information       = FaceHelper_Exit_Info ;
           important       = FALSE;
           permanent       = TRUE;
           description       = "dummy";
    };
    
    FUNC INT FaceHelper_BodyTex_Change_Condition () {
           if (PLAYER_MOBSI_PRODUCTION == MOBSI_FACEHELPER) {
                  //Figure out if we need to reset InfoManagerSpinnerValue value
                  var string lastSpinnerID; //Actually global variable! ;-)
    
                  if (Hlp_StrCmp (InfoManagerSpinnerID, "2")) {
                         //Setup spinner if spinner ID has changed
                         if (!Hlp_StrCmp (InfoManagerSpinnerID, lastSpinnerID)) {
                                InfoManagerSpinnerValue = FaceHelper_BodyTex;
                         };
    
                         InfoManagerSpinnerValueMin = 0;
                         InfoManagerSpinnerValueMax = FaceHelper_BodyTex_Max;
    
                         //Update Face Helper visual if spinner changed
                         if (FaceHelper_BodyTex != InfoManagerSpinnerValue) {
                                FaceHelper_BodyTex = InfoManagerSpinnerValue;
                                FH_ChangeVisual ();
                         };
                  };
    
                  lastSpinnerID = InfoManagerSpinnerID;
    
                  var string newDescription;
    
                  //Spinner ID 2
                  newDescription = "s@2 <-- BodyTex --> ";
                  newDescription = ConcatStrings (newDescription, IntToString (FaceHelper_BodyTex));
                  newDescription = ConcatStrings (newDescription, " / ");
                  newDescription = ConcatStrings (newDescription, IntToString (FaceHelper_BodyTex_Max));
    
                  //Update description
                  FaceHelper_BodyTex_Change.description = newDescription;
                  
                  return TRUE;
           };
    
           return FALSE;
    };
    
    INSTANCE FaceHelper_Skin_Change (C_Info) {
           nr              = 15;
           condition       = FaceHelper_Skin_Change_Condition;
           information       = FaceHelper_Exit_Info ;
           important       = FALSE;
           permanent       = TRUE;
           description       = "dummy";
    };
    
    FUNC INT FaceHelper_Skin_Change_Condition ()
    {
           if (PLAYER_MOBSI_PRODUCTION == MOBSI_FACEHELPER) {
                  //Figure out if we need to reset InfoManagerSpinnerValue value
                  var string lastSpinnerID; //Actually global variable! ;-)
    
                  if (Hlp_StrCmp (InfoManagerSpinnerID, "3")) {
                         //Setup spinner if spinner ID has changed
                         if (!Hlp_StrCmp (InfoManagerSpinnerID, lastSpinnerID)) {
                                InfoManagerSpinnerValue = FaceHelper_Skin;
                         };
    
                         InfoManagerSpinnerValueMin = 0;
                         InfoManagerSpinnerValueMax = FaceHelper_Skin_Max;
    
                         //Update Face Helper visual if spinner changed
                         if (FaceHelper_Skin != InfoManagerSpinnerValue) {
                                FaceHelper_Skin = InfoManagerSpinnerValue;
                                FH_ChangeVisual ();
                         };
                  };
    
                  lastSpinnerID = InfoManagerSpinnerID;
    
                  var string newDescription;
    
                  //Spinner ID 3
                  newDescription = "s@3 <-- Skin --> ";
                  newDescription = ConcatStrings (newDescription, IntToString (FaceHelper_Skin));
                  newDescription = ConcatStrings (newDescription, " / ");
                  newDescription = ConcatStrings (newDescription, IntToString (FaceHelper_Skin_Max));
    
                  //Update description
                  FaceHelper_Skin_Change.description = newDescription;
                  
                  return TRUE;
           };
    
           return FALSE;
    };
    
    INSTANCE FaceHelper_HeadTex_Change (C_Info) {
           nr              = 20;
           condition       = FaceHelper_HeadTex_Change_Condition;
           information       = FaceHelper_Exit_Info ;
           important       = FALSE;
           permanent       = TRUE;
           description       = "dummy";
    };
    
    FUNC INT FaceHelper_HeadTex_Change_Condition () {
           if (PLAYER_MOBSI_PRODUCTION == MOBSI_FACEHELPER) {
                  //Figure out if we need to reset InfoManagerSpinnerValue value
                  var string lastSpinnerID; //Actually global variable! ;-)
                  
                  if (Hlp_StrCmp (InfoManagerSpinnerID, "4")) {
                         //Setup spinner if spinner ID has changed
                         if (!Hlp_StrCmp (InfoManagerSpinnerID, lastSpinnerID)) {
                                InfoManagerSpinnerValue = FaceHelper_HeadTex;
                         };
    
                         InfoManagerSpinnerValueMin = 0;
                         InfoManagerSpinnerValueMax = FaceHelper_HeadTex_Max;
    
                         //Update Face Helper visual if spinner changed
                         if (FaceHelper_HeadTex != InfoManagerSpinnerValue) {
                                FaceHelper_HeadTex = InfoManagerSpinnerValue;
                                FH_ChangeVisual ();
                         };
                  };
    
                  lastSpinnerID = InfoManagerSpinnerID;
    
                  var string newDescription;
    
                  //Spinner ID 4
                  newDescription = "s@4 <-- HeadTex --> ";
                  newDescription = ConcatStrings (newDescription, IntToString (FaceHelper_HeadTex));
                  newDescription = ConcatStrings (newDescription, " / ");
                  newDescription = ConcatStrings (newDescription, IntToString (FaceHelper_HeadTex_Max));
    
                  //Update description
                  FaceHelper_HeadTex_Change.description = newDescription;
                  
                  return TRUE;
           };
    
           return FALSE;
    };
    
    INSTANCE FaceHelper_TeethTex_Change (C_Info) {
           nr              = 25;
           condition       = FaceHelper_TeethTex_Change_Condition;
           information       = FaceHelper_Exit_Info ;
           important       = FALSE;
           permanent       = TRUE;
           description       = "dummy";
    };
    
    FUNC INT FaceHelper_TeethTex_Change_Condition () {
           if (PLAYER_MOBSI_PRODUCTION == MOBSI_FACEHELPER) {
                  //Figure out if we need to reset InfoManagerSpinnerValue value
                  var string lastSpinnerID; //Actually global variable! ;-)
                  
                  if (Hlp_StrCmp (InfoManagerSpinnerID, "5")) {
                         //Setup spinner if spinner ID has changed
                         if (!Hlp_StrCmp (InfoManagerSpinnerID, lastSpinnerID)) {
                                InfoManagerSpinnerValue = FaceHelper_TeethTex;
                         };
    
                         InfoManagerSpinnerValueMin = 0;
                         InfoManagerSpinnerValueMax = FaceHelper_TeethTex_Max;
    
                         //Update Face Helper visual if spinner changed
                         if (FaceHelper_TeethTex != InfoManagerSpinnerValue) {
                                FaceHelper_TeethTex = InfoManagerSpinnerValue;
                                FH_ChangeVisual ();
                         };
                  };
    
                  lastSpinnerID = InfoManagerSpinnerID;
    
                  var string newDescription;
    
                  //Spinner ID 5
                  newDescription = "s@5 <-- TeethTex --> ";
                  newDescription = ConcatStrings (newDescription, IntToString (FaceHelper_TeethTex));
                  newDescription = ConcatStrings (newDescription, " / ");
                  newDescription = ConcatStrings (newDescription, IntToString (FaceHelper_TeethTex_Max));
    
                  //Update description
                  FaceHelper_TeethTex_Change.description = newDescription;
                  
                  return TRUE;
           };
    
           return FALSE;
    };
    
    INSTANCE FaceHelper_Armor_Change (C_Info) {
           nr              = 30;
           condition       = FaceHelper_Armor_Change_Condition;
           information       = FaceHelper_Exit_Info ;
           important       = FALSE;
           permanent       = TRUE;
           description       = "dummy";
    };
    
    FUNC INT FaceHelper_Armor_Change_Condition ()
    {
           if (PLAYER_MOBSI_PRODUCTION == MOBSI_FACEHELPER) {
                  //Figure out if we need to reset InfoManagerSpinnerValue value
                  var string lastSpinnerID; //Actually global variable! ;-)
                  
                  if (Hlp_StrCmp (InfoManagerSpinnerID, "6")) {
                         //Setup spinner if spinner ID has changed
                         if (!Hlp_StrCmp (InfoManagerSpinnerID, lastSpinnerID)) {
                                InfoManagerSpinnerValue = FaceHelper_Armor;
                         };
    
                         InfoManagerSpinnerValueMin = -1;
                         InfoManagerSpinnerValueMax = FaceHelper_Armor_Max;
    
                         //Update Face Helper visual if spinner changed
                         if (FaceHelper_Armor != InfoManagerSpinnerValue) {
                                FaceHelper_Armor = InfoManagerSpinnerValue;
    
                                if (FaceHelper_Armor == -1) { FaceHelper_Armor_Name = "NO ARMOR"; FaceHelper_Armor_Instance = -1; } else
                                if (FaceHelper_Armor == 0) { FaceHelper_Armor_Name = "VLK_ARMOR_L"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (VLK_ARMOR_L); } else
                                if (FaceHelper_Armor == 1) { FaceHelper_Armor_Name = "VLK_ARMOR_M"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (VLK_ARMOR_M); } else
    
                                if (FaceHelper_Armor == 2) { FaceHelper_Armor_Name = "SFB_ARMOR_L"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (SFB_ARMOR_L); } else
    
                                if (FaceHelper_Armor == 3) { FaceHelper_Armor_Name = "TPL_ARMOR_L"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (TPL_ARMOR_L); } else
                                if (FaceHelper_Armor == 4) { FaceHelper_Armor_Name = "TPL_ARMOR_M"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (TPL_ARMOR_M); } else
                                if (FaceHelper_Armor == 5) { FaceHelper_Armor_Name = "TPL_ARMOR_H"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (TPL_ARMOR_H); } else
                                
                                if (FaceHelper_Armor == 6) { FaceHelper_Armor_Name = "STT_ARMOR_M"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (STT_ARMOR_M); } else
                                if (FaceHelper_Armor == 7) { FaceHelper_Armor_Name = "STT_ARMOR_H"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (STT_ARMOR_H); } else
    
                                if (FaceHelper_Armor == 8) { FaceHelper_Armor_Name = "GRD_ARMOR_L"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (GRD_ARMOR_L); } else
                                if (FaceHelper_Armor == 9) { FaceHelper_Armor_Name = "GRD_ARMOR_M"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (GRD_ARMOR_M); } else
                                if (FaceHelper_Armor == 10) { FaceHelper_Armor_Name = "GRD_ARMOR_H"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (GRD_ARMOR_H); } else
    
                                if (FaceHelper_Armor == 11) { FaceHelper_Armor_Name = "KDF_ARMOR_L"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (KDF_ARMOR_L); } else
                                if (FaceHelper_Armor == 12) { FaceHelper_Armor_Name = "KDF_ARMOR_H"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (KDF_ARMOR_H); } else
    
                                if (FaceHelper_Armor == 13) { FaceHelper_Armor_Name = "KDW_ARMOR_L"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (KDW_ARMOR_L); } else
                                if (FaceHelper_Armor == 14) { FaceHelper_Armor_Name = "KDW_ARMOR_H"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (KDW_ARMOR_H); } else
    
                                if (FaceHelper_Armor == 15) { FaceHelper_Armor_Name = "GUR_ARMOR_M"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (GUR_ARMOR_M); } else
                                if (FaceHelper_Armor == 16) { FaceHelper_Armor_Name = "GUR_ARMOR_H"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (GUR_ARMOR_H); } else
    
                                if (FaceHelper_Armor == 17) { FaceHelper_Armor_Name = "ORG_ARMOR_L"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (ORG_ARMOR_L); } else
                                if (FaceHelper_Armor == 18) { FaceHelper_Armor_Name = "ORG_ARMOR_M"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (ORG_ARMOR_M); } else
                                if (FaceHelper_Armor == 19) { FaceHelper_Armor_Name = "ORG_ARMOR_H"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (ORG_ARMOR_H); } else
    
                                if (FaceHelper_Armor == 20) { FaceHelper_Armor_Name = "SLD_ARMOR_L"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (SLD_ARMOR_L); } else
                                if (FaceHelper_Armor == 21) { FaceHelper_Armor_Name = "SLD_ARMOR_M"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (SLD_ARMOR_M); } else
                                if (FaceHelper_Armor == 22) { FaceHelper_Armor_Name = "SLD_ARMOR_H"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (SLD_ARMOR_H); } else
    
                                if (FaceHelper_Armor == 23) { FaceHelper_Armor_Name = "NOV_ARMOR_L"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (NOV_ARMOR_L); } else
                                if (FaceHelper_Armor == 24) { FaceHelper_Armor_Name = "NOV_ARMOR_M"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (NOV_ARMOR_M); } else
                                if (FaceHelper_Armor == 25) { FaceHelper_Armor_Name = "NOV_ARMOR_H"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (NOV_ARMOR_H); } else
    
                                if (FaceHelper_Armor == 26) { FaceHelper_Armor_Name = "CRW_ARMOR_H"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (CRW_ARMOR_H); } else
                                if (FaceHelper_Armor == 27) { FaceHelper_Armor_Name = "DMB_ARMOR_M"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (DMB_ARMOR_M); } else
                                
                                if (FaceHelper_Armor == 28) { FaceHelper_Armor_Name = "ORE_ARMOR_M"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (ORE_ARMOR_M); } else
                                if (FaceHelper_Armor == 29) { FaceHelper_Armor_Name = "ORE_ARMOR_H"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (ORE_ARMOR_H); } else
    
                                if (FaceHelper_Armor == 30) { FaceHelper_Armor_Name = "EBR_ARMOR_M"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (EBR_ARMOR_M); } else
                                if (FaceHelper_Armor == 31) { FaceHelper_Armor_Name = "EBR_ARMOR_H"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (EBR_ARMOR_H); } else
                                if (FaceHelper_Armor == 32) { FaceHelper_Armor_Name = "EBR_ARMOR_H2"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (EBR_ARMOR_H2); } else
    
                                if (FaceHelper_Armor == 33) { FaceHelper_Armor_Name = "GRD_ARMOR_I"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (GRD_ARMOR_I); } else
                                if (FaceHelper_Armor == 34) { FaceHelper_Armor_Name = "PIRATE_ARMOR_M"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (PIRATE_ARMOR_M); } else
                                if (FaceHelper_Armor == 35) { FaceHelper_Armor_Name = "DEMENTOR_ARMOR"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (DEMENTOR_ARMOR); } else
                                if (FaceHelper_Armor == 36) { FaceHelper_Armor_Name = "LAW_ARMOR"; FaceHelper_Armor_Instance = Hlp_GetInstanceID (LAW_ARMOR); };
    
                                FH_ChangeVisual ();
                         };
                  };
    
                  lastSpinnerID = InfoManagerSpinnerID;
    
                  var string newDescription;
    
                  //Spinner ID 6
                  newDescription = "s@6 <-- ";
    
                  newDescription = ConcatStrings (newDescription, FaceHelper_Armor_Name);
                  newDescription = ConcatStrings (newDescription, " --> ");
                  newDescription = ConcatStrings (newDescription, IntToString (FaceHelper_Armor));
                  newDescription = ConcatStrings (newDescription, " / ");
                  newDescription = ConcatStrings (newDescription, IntToString (FaceHelper_Armor_Max));
    
                  //Update description
                  FaceHelper_Armor_Change.description = newDescription;
                  
                  return TRUE;
           };
    
           return FALSE;
    };
    
    FUNC VOID FH_Dialogs () {
           PLAYER_MOBSI_PRODUCTION = MOBSI_FACEHELPER;
    
           FaceHelper_Exit.npc = Hlp_GetInstanceID (hero);
           FaceHelper_HeadMesh_Change.npc = Hlp_GetInstanceID (hero);
           FaceHelper_BodyTex_Change.npc = Hlp_GetInstanceID (hero);
           FaceHelper_Skin_Change.npc = Hlp_GetInstanceID (hero);
           FaceHelper_HeadTex_Change.npc = Hlp_GetInstanceID (hero);
           FaceHelper_TeethTex_Change.npc = Hlp_GetInstanceID (hero);
           FaceHelper_Armor_Change.npc = Hlp_GetInstanceID (hero);
    
           AI_ProcessInfos (hero);
    };

    3. Sleep a bit
    Script uses functions Wld_GetHour & Wld_GetMinute from Nodrog:
    https://forum.worldofplayers.de/foru...=1#post7741998
    Code:
    func void PC_Sleep (var int t) {
           AI_StopProcessInfos (self);
           self.aivar[AIV_INVINCIBLE] = FALSE;
    
           if (Wld_IsTime (00, 00, t, 00)) {
                  Wld_SetTime (t, 00);
           } else {
                  t = t + 24;
                  Wld_SetTime (t, 00);
           };
    
           PrintScreen ("You slept well and feel better", -1,-1,"font_old_20_white.tga",3);
    
           hero.attribute[ATR_HITPOINTS] = hero.attribute[ATR_HITPOINTS_MAX];
           hero.attribute[ATR_MANA] = hero.attribute[ATR_MANA_MAX];       
    
           Npc_SendPassivePerc (hero, PERC_ASSESSENTERROOM, NULL, hero);
    };
    
    INSTANCE PC_NoSleep (c_Info) {
           npc              = PC_Hero;
           nr              = 999;
           condition       = PC_NoSleep_Condition;
           information       = PC_NoSleep_Info;
           important       = 0;
           permanent       = 1;
           description       = DIALOG_ENDE; 
    };
    
    FUNC INT PC_NoSleep_Condition () {              
           return 1;
    };
    
    func VOID PC_NoSleep_Info () {
           PLAYER_MOBSI_PRODUCTION = MOBSI_DIALOG_NONE;
    
           AI_StopProcessInfos (self);
           self.aivar[AIV_INVINCIBLE] = FALSE;
    };
    
    instance PC_Sleep_SetHour (C_Info)
    {
           nr              = 1;
           condition       = PC_Sleep_SetHour_Condition;
           information       = PC_Sleep_SetHour_Info;
           important       = FALSE;
           permanent       = TRUE;
           description       = "dummy";
    };
    
    FUNC INT PC_Sleep_SetHour_Condition ()
    {
           if (PLAYER_MOBSI_PRODUCTION == MOBSI_DIALOG_SLEEP) {
                  //Figure out if we need to reset InfoManagerSpinnerValue value
                  var string lastSpinnerID; //Actually global variable! ;-)
                  
                  const int sleepHour = -1;
    
                  if (Hlp_StrCmp (InfoManagerSpinnerID, "1")) {
                         //Setup spinner if spinner ID has changed
                         if (!Hlp_StrCmp (InfoManagerSpinnerID, lastSpinnerID)) {
                                InfoManagerSpinnerValue = Wld_GetHour (0, 23) + 1;
                         };
    
                         //Page Up/Down value
                         InfoManagerSpinnerPageSize = 4;
    
                         InfoManagerSpinnerValueMin = 0;
                         InfoManagerSpinnerValueMax = 23;
                         
                         sleepHour = InfoManagerSpinnerValue;
                  };
    
                  lastSpinnerID = InfoManagerSpinnerID;
    
                  var string newDescription;
    
                  //Spinner ID 1
                  newDescription = "s@1 Current time: ";
    
                  var int hh; hh = Wld_GetHour (0, 23);
                  var int mm; mm = Wld_GetMinute (hh, 0, 59);
    
                  if (hh < 10) {
                         newDescription = ConcatStrings (newDescription, "0");
                  };
    
                  newDescription = ConcatStrings (newDescription, IntToString (hh));
                  newDescription = ConcatStrings (newDescription, ":");
    
                  if (mm < 10) {
                         newDescription = ConcatStrings (newDescription, "0");
                  };
    
                  newDescription = ConcatStrings (newDescription, IntToString (mm));
    
                  newDescription = ConcatStrings (newDescription, " sleep until time: ");
    
                  if (sleepHour < 10) {
                         newDescription = ConcatStrings (newDescription, "0");
                  };
    
                  newDescription = ConcatStrings (newDescription, IntToString (sleepHour));
                  newDescription = ConcatStrings (newDescription, ":00");
    
                  //Update description
                  PC_Sleep_SetHour.description = newDescription;
                  
                  return TRUE;
           };
    
           return FALSE;
    };
    
    
    func void PC_Sleep_SetHour_Info () {
           PC_Sleep (InfoManagerSpinnerValue);
    };
    
    func void SLEEPABIT_S1 () {
           var C_NPC her;        her = Hlp_GetNpc(PC_Hero); 
           var C_NPC rock; rock = Hlp_GetNpc(PC_Rockefeller);
           
           if ((Hlp_GetInstanceID (self) == Hlp_GetInstanceID (her)) || (Hlp_GetInstanceID (self) == Hlp_GetInstanceID (rock)))        {
                  PLAYER_MOBSI_PRODUCTION = MOBSI_DIALOG_SLEEP;
                  self.aivar[AIV_INVINCIBLE] = TRUE;
    
                  //Default
                  InfoManagerSpinnerID = "";
                  InfoManagerSpinnerValue = Wld_GetHour (0, 23) + 1;
    
                  PC_NoSleep.npc = Hlp_GetInstanceID (self);
                  PC_Sleep_SetHour.npc = Hlp_GetInstanceID (self);
    
                  AI_ProcessInfos (self);
           };
    };
    Let me know in case you face any issues
    Geändert von F a w k e s (19.09.2020 um 21:30 Uhr)

  16. Beiträge anzeigen #16 Zitieren
    Legende der Amazonen Avatar von Bisasam
    Registriert seit
    Dec 2006
    Ort
    Meine Faust in Sinis Gesicht
    Beiträge
    9.639
     
    Bisasam ist offline
    Thanks for sharing your code! Isn't strings.d already covered by LeGo or am I mistaking something?
    I'm also unsure when to parse this. After the dialogue scripts or just right after Ikarus and LeGo?

    I'll also make my important choices red now instead of writing ENTSCHEIDUNG in front of it. Will work better.
    And creating items will be much better with your newest addition


    "Das erinnert doch sehr erfreulich an das, was man sich als Gothicfan wünscht!"
    -Korallenkette

  17. Beiträge anzeigen #17 Zitieren
    Local Hero
    Registriert seit
    Feb 2017
    Beiträge
    270
     
    F a w k e s ist offline
    Hello Bisasam, both strings.d and convert.d packages are still required, as script uses function hex2dec (convert.d), hex2dec then uses STR_ReplaceAll (strings.d). I think none of these are available in LeGo, only issue you might have with strings.d is function STR_Lower - comment that one out (it was part of Ikarus 1.2.2 I had to comment it out).
    As for parsing - you can parse these functions after LeGo, that's how I am doing it (I hope I dind't forget anything, let me know in case you see something is wrong)

  18. Beiträge anzeigen #18 Zitieren
    banned
    Registriert seit
    Jan 2009
    Ort
    Oberösterreich
    Beiträge
    2.393
     
    Moe ist offline
    Wow F a w k e s! I am mega thankful and impressed with your awesome work!

  19. Beiträge anzeigen #19 Zitieren
    Local Hero
    Registriert seit
    Feb 2017
    Beiträge
    270
     
    F a w k e s ist offline
    @Moe I am thankful to Bisasam, without inspiration coming from her post it would probably not occur to me to try this !

    Script in first post updated one more time. I have added two things:
    - 'spinner' dialog indicator in right corner '<>' hinting that you can use left-right arrows:
    'answer' dialog indicator is three dots '...', probably not required as much, but wont harm.

    - text alignment option, by adjusting constant InfoManagerDefaultDialogAlignment you can control alignment of all dialog options. When value is 0 (default), text is aligned to left, when value is 1 text is aligned in center of screen, when value is 2 text is aligned to right. Below example with alignment of all texts in center:
    + added new modifiers in case someone would want to use text alignment on individual dialogs "al@" align left, "ac@" align center, "ar@" align right.

  20. Beiträge anzeigen #20 Zitieren
    Serima Avatar von Fisk2033
    Registriert seit
    Dec 2010
    Ort
    Dresden
    Beiträge
    5.803
     
    Fisk2033 ist offline
    Wow! Thanks for sharing!

Seite 1 von 2 12 Letzte »

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
Impressum | Link Us | intern
World of Gothic © by World of Gothic Team
Gothic, Gothic 2 & Gothic 3 are © by Piranha Bytes & Egmont Interactive & JoWooD Productions AG, all rights reserved worldwide