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

 

Ergebnis 1 bis 16 von 16
  1. Beiträge anzeigen #1 Zitieren
    Krieger Avatar von Noxum
    Registriert seit
    Sep 2006
    Ort
    Worms
    Beiträge
    453
     
    Noxum ist offline

    Gothic1 Taschendiebstahl - Genauere Analyse und Verbesserungspotential

    Hallo Community,

    es gibt zahlreiche Threads zum Thema G1 Taschendiebstahl und wie dieser anzuwenden ist. Hier soll es etwas mehr ins Detail gehen.
    Die durchgängige Meinung besagt, dass in Gothic 1 der Taschendiebstahl unbrauchbar ist, da:
    1. Zu viele LP kostet
    2. Er eh immer fehlschlägt
    3. Es nichts kostbares zu Ergaunern gibt
    4. Nur namenlose NPC's beklaut werden können

    Mein Ziel ist es den Taschendiebstahl zu verbessern. Punkt 1 und 3 lassen sich leicht ändern, indem man LP-Kosten herabsetzt und wertvollere Items verteilt. Ich vermute Punkt 4 lässt sich in den Script-Einstellungen des NPC's verändern. Kann das jemand bestätigen?

    Der Punkt 2 ist mir noch nicht ganz klar. Woran hängt die Erfolgschance des Diebstahls ab? In Gothic 2 gibt es dazu eine Mapping Liste (Dex 10-20 ein Kinderspiel, Dex 21 - 40 einfach, usw.). In Gothic 1 in der Charakterübersicht gibt es eine prozentuale Angabe (z.B. 10%).
    Unschön wäre, wenn die Logik wirklich nur auf Basis von Taschendiebstahl Stufe 1 und 2 "würfelt", ob ein Diebstahl erfolgreich ist oder nicht. Eine Erhöhung der prozentualen Werte wäre ein Anfang.

    Was denkt ihr zum Thema?
    Ist der Taschendiebstahl in Gothic 1 noch zu retten, sofern man diesen verbessert und eine chronische Geldknappheit (über den ganzen Spielverlauf hinweg) schafft?

    Noxum

  2. Beiträge anzeigen #2 Zitieren
    Ritter Avatar von aebo
    Registriert seit
    Oct 2008
    Beiträge
    1.278
     
    aebo ist offline
    Zitat Zitat von Noxum Beitrag anzeigen
    Hallo Community,

    es gibt zahlreiche Threads zum Thema G1 Taschendiebstahl und wie dieser anzuwenden ist. Hier soll es etwas mehr ins Detail gehen.
    Die durchgängige Meinung besagt, dass in Gothic 1 der Taschendiebstahl unbrauchbar ist, da:
    1. Zu viele LP kostet
    2. Er eh immer fehlschlägt
    3. Es nichts kostbares zu Ergaunern gibt
    4. Nur namenlose NPC's beklaut werden können

    Mein Ziel ist es den Taschendiebstahl zu verbessern. Punkt 1 und 3 lassen sich leicht ändern, indem man LP-Kosten herabsetzt und wertvollere Items verteilt. Ich vermute Punkt 4 lässt sich in den Script-Einstellungen des NPC's verändern. Kann das jemand bestätigen?

    Der Punkt 2 ist mir noch nicht ganz klar. Woran hängt die Erfolgschance des Diebstahls ab? In Gothic 2 gibt es dazu eine Mapping Liste (Dex 10-20 ein Kinderspiel, Dex 21 - 40 einfach, usw.). In Gothic 1 in der Charakterübersicht gibt es eine prozentuale Angabe (z.B. 10%).
    Unschön wäre, wenn die Logik wirklich nur auf Basis von Taschendiebstahl Stufe 1 und 2 "würfelt", ob ein Diebstahl erfolgreich ist oder nicht. Eine Erhöhung der prozentualen Werte wäre ein Anfang.

    Was denkt ihr zum Thema?
    Ist der Taschendiebstahl in Gothic 1 noch zu retten, sofern man diesen verbessert und eine chronische Geldknappheit (über den ganzen Spielverlauf hinweg) schafft?

    Noxum
    Moin Noxum,

    zu Punkt 2.
    ich habe den Taschendiebstahl so verändert, das die Npc's anders auf das Schleichen außerhalb von Portalräumen reagieren. Soll heißen: Die Npc's nehmen zwar wahr das der Held schleicht aber sie machen nicht alle anderen Npc's darauf aufmerksam sodass sich alle zu dem Held drehen. Damit funktioniert das ganz gut
    Das Wappen
    -Eine fantastische Spielwelt erwartet dich-
    -bis zu 100 Stunden Spielzeit-

  3. Beiträge anzeigen #3 Zitieren
    Local Hero
    Registriert seit
    Feb 2017
    Beiträge
    270
     
    F a w k e s ist offline
    Zitat Zitat von Noxum Beitrag anzeigen
    4. Nur namenlose NPC's beklaut werden können
    In G1 there is a file G_CanSteal.d where following function defines which NPC can be pickpocketed:
    Code:
    func int G_CanSteal()
    {
    	if((other.npcType != npctype_friend) && (other.npcType != npctype_main))
    	{
    		return TRUE;
    	};
    	PrintScreen(_STR_MESSAGE_CANNOTSTEAL,-1,_YPOS_MESSAGE_CANNOTSTEAL,_STR_FONT_ONSCREEN,_TIME_MESSAGE_CANNOTSTEAL);
    	return FALSE;
    };

  4. Beiträge anzeigen #4 Zitieren
    Krieger Avatar von Noxum
    Registriert seit
    Sep 2006
    Ort
    Worms
    Beiträge
    453
     
    Noxum ist offline
    Zitat Zitat von aebo Beitrag anzeigen
    Moin Noxum,

    zu Punkt 2.
    ich habe den Taschendiebstahl so verändert, das die Npc's anders auf das Schleichen außerhalb von Portalräumen reagieren. Soll heißen: Die Npc's nehmen zwar wahr das der Held schleicht aber sie machen nicht alle anderen Npc's darauf aufmerksam sodass sich alle zu dem Held drehen. Damit funktioniert das ganz gut
    Sers Aebo,

    verrätst du mir, welches Script du dazu angepasst hast?

    Zuletzt müsste man nur noch wissen, wie sich die Wahrscheinlichkeit für den Erfolg eines Diebstahls berechnet. Also in welchem Script die Berechnung für die 2 (beziehungsweise 3) Stufen geschieht.

    Level 0: No theft is possible
    Level 1: ???
    Level 2: ???

    In den Script-Files finde ich nichts, was weiterhelfen könnte.
    Vermutlich das gleiche Script, dass die Volltrefferwahrscheinlichkeit bei Einhand- und Zweihandwaffen berechnet (0, 5 oder 10 Prozent).

    @F a w k e s: Thank you for the hint. One more piece to complete the puzzle.

  5. Beiträge anzeigen #5 Zitieren
    Ritter Avatar von aebo
    Registriert seit
    Oct 2008
    Beiträge
    1.278
     
    aebo ist offline
    Zitat Zitat von Noxum Beitrag anzeigen
    Sers Aebo,

    verrätst du mir, welches Script du dazu angepasst hast?

    Zuletzt müsste man nur noch wissen, wie sich die Wahrscheinlichkeit für den Erfolg eines Diebstahls berechnet. Also in welchem Script die Berechnung für die 2 (beziehungsweise 3) Stufen geschieht.

    Level 0: No theft is possible
    Level 1: ???
    Level 2: ???

    In den Script-Files finde ich nichts, was weiterhelfen könnte.
    Vermutlich das gleiche Script, dass die Volltrefferwahrscheinlichkeit bei Einhand- und Zweihandwaffen berechnet (0, 5 oder 10 Prozent).

    @F a w k e s: Thank you for the hint. One more piece to complete the puzzle.
    Hi Noxum,

    habe gerade nochmal gelesen, dass du ja in G1 den Taschendiebstahl verbessern möchtest. Ich habe in G2 den G1 Taschendiebstahl implementiert und auch in G2 die Wahrnehmungen verändert. Ich weiß nicht wo genau das in G1 gemacht wird. Könnte mich die Tage aber mal dransetzen. Müsste ja vergleichbares dort zu finden geben.
    Das Wappen
    -Eine fantastische Spielwelt erwartet dich-
    -bis zu 100 Stunden Spielzeit-

  6. Beiträge anzeigen #6 Zitieren
    Krieger Avatar von Noxum
    Registriert seit
    Sep 2006
    Ort
    Worms
    Beiträge
    453
     
    Noxum ist offline
    Wow das ist auch mal nicht schlecht!
    Hast du dann auch den zweistufigen Ansatz von Gothic 1 übernommen oder bist bei den mehrstufigen Prinzip von Gothic 2, der auf Geschicklichkeit basiert, geblieben?

    Habe mit Scripts bisher leider nie gearbeitet. Nicht mal einen NPC erstellt
    Werde mich in das Thema erst etwas einarbeiten müssen (sobald das Welt-Mesh fertiggestellt ist)..

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

    G1 Pickpocketing

    Hi Noxum,
    I have implemented in my G1 modification a different method of Pickpocketing - hybrid of both worlds G1 & G2A.
    1. Pickpocketing is activated via dialog.
    2. Player can steal items from NPC only when his dexterity > NPCs dexterity.
    3. There is no punishment for pickpocketing. You cannot be caught while stealing.
    4. Player has access to all (with the exception of equipped items) items, but he can steal only 1 item.

    Based on my own experience (I have spent hours by saving - reloading the game when I have failed in pickpocketing) I have decided that punishment is unnecessary evil, and pointless save-reload is way too frustrating to be part of my mod. Instead of punishing the player - I've tried to put more emphasis on the loot. Each NPC, from which you can steal something will have in its inventory several interesting items - which makes pickpocketing more satisfying.

    For example Huno:
    1. Key to his chest - where you can find nice Sword.
    2. A letter, which leads you to secret Quest upon reading.
    3. Ring which will increase your strength by 5 points.
    + randomly generated crap

    [Video]

    How does it work?
    Simplified explanation - when player activates pickpocketing dialog:
    1. Npc StealHelper will be inserted into a world to waypoint "TOT". Npc is by default dead, and wont despawn as it is wearing armor with item flag ITEM_MISSION.
    2. Complete inventory (excluding equipped items) will be transferred from victim to StealHelper.
    3. We will call NPC_OpenDeadNpc on StealHelper - this will open StealHelpers inventory.
    4. Hooks will check whether player transferred an item or closed inventory:
    a) if he transferred (stole) an item - rest of the inventory will be transferred back from StealHelper to victim.
    b) if he closed inventory (canceled action) - items will be transferred back from StealHelper to victim.

    Complete code below - most likely there is more elegant way - I am opened to any constructive criticism

    Required:
    Ikarus 1.2.1
    LeGo 2.5.1

    1. We have to disable original G1 pickpocketing system - simply by always returning FALSE value from function G_CanSteal:
    Code:
    FUNC INT G_CanSteal ()
    {
        return FALSE;
    };
    2. Couple of global variables, constants and instances:
    Code:
        //Dialog description
        const string DIALOG_PICKPOCKET = "(pickpocket)";
    
        //XP points
        const int XP_Bonus_PickPocketing        = 5;
    
        //New variable for Player Talent - PickPocketing
        var int vPT_PickPocketing;
    
        //Number of pickpocketed NPCs (player will get increasing XP per each stolen item)
        var int vPT_PickPocketing_Counter;
    
        //New variable which will tell us what is happening in our pickpocketing system
        var int PickPocketing_Dialog;
            const int cPP_Dialog_Default        = 0;    //Default - pickpocketing dialog is not running
            const int cPP_Dialog_Selected        = 1;    //Dialog was selected, inventory was transfered from StealVictim to StealHelper, StealHelper was killed and his inventory opened
            const int cPP_Dialog_Done        = 2;    //Player stole an item
            const int cPP_Dialog_Canceled        = 3;    //Player canceled action
    
        //Variable identifying Victim
        INSTANCE StealVictim (C_NPC);
    
        //Armor, which will prevent our StealHelper from despawning
        INSTANCE ARMOR_PREVENT_DESPAWN (C_Item)
        {
            name            = "Dummy armor";
            mainflag        = ITEM_KAT_ARMOR | ITEM_MISSION;        //flag ITEM_MISSION prevents NPC wearing this armor from despawning !
            Flags            = 0;
            
            protection[PROT_EDGE]    = 0;
            protection[PROT_BLUNT]    = 0;
            protection[PROT_POINT]    = 0;
            protection[PROT_FIRE]    = 0;
            protection[PROT_MAGIC]    = 0;
            
            value            = 0;
            cond_value [2]        = 0;
    
            wear            = WEAR_TORSO;
            ownerGuild        = GIL_EBR;
            visual            = "ebrh2.3ds";
            visual_change        = "Hum_EBRS_ARMOR2.asc";
            visual_skin        = 0;
            material        = MAT_METAL;
    
            description        = name;
            text[1] = NAME_Prot_Edge;    count[1] = protection[PROT_EDGE];
            text[2] = NAME_Prot_Point;    count[2] = protection[PROT_POINT];
            text[3] = NAME_Prot_Fire;    count[3] = protection[PROT_FIRE];
            text[4] = NAME_Prot_Magic;    count[4] = protection[PROT_MAGIC];
            text[5] = NAME_Value;        count[5] = value;
        };    
    
        //StealHelper. We will use him to transfer Victims inventory into his inventory and let player open his inventory to access items
        INSTANCE StealHelper (C_NPC)
        {
            name                = "StealHelper";
            id                = 2500;
            attribute [ATR_HITPOINTS_MAX]    = 1;
            attribute [ATR_HITPOINTS]    = -1;    //NPC is dead by default
    
            Mdl_SetVisual (self, "HUMANS.MDS");
            Mdl_SetVisualBody (self, "hum_body_Naked0", 0, 1, "Hum_Head_FatBald", 79, 1, ARMOR_PREVENT_DESPAWN);
        };
    
        //Variable indicating that something was transferred via functions NPC_Transfer_Inventory_Category / NPC_Transfer_Inventory
        var int InventoryTransferred;
    3. As per my rules for new pickpocketing system I wanted to let player steal only 1 single item. Therefore each NPC should be able to 'tell' us whether player stole something from him or
    not. For this purpose we will use 1 variable in array NPC.aivar[0..49]. In vanilla Gothic 1 NPC uses only variables from range 0..42. We can therefore reserve one constant (let's say #43) for our purposes:
    Code:
    const int AIV_MOD_PICKPOCKET                = 43;
        const int cPickPocketed_NotYet            = 0;    //Player didn't steal anything yet.
        const int cPickPocketed_Yes            = 1;    //Player already stole something from NPC.
    4. Functions which will take care of inventory transfer from StealVictim to StealHelper and vice-versa:
    Code:
    /***
        Function will transfer Inventory Category (for example all weapons INV_WEAPON) from slf to oth.
        transferEquippedItems: FALSE will not transfer equipped items
        transferMissionItems: FALSE will not transfer mission items
    ***/
    FUNC VOID NPC_Transfer_Inventory_Category (var C_NPC slf, var C_NPC oth, var int invCategory, var int transferEquippedItems, var int transferMissionItems)
    {
        var int p;
        var int itmCount;
        var int itmInstance;
        
        var int itmSlot;
        
        itmSlot = 0;
        
        //Loop
        p = MEM_StackPos.position;
    
        //Is there any item in this inventory category ?
        if (NPC_GetInvItemBySlot (slf, invCategory, itmSlot) > 0)
        {
            itmInstance = Hlp_GetInstanceID (item);
    
            //Should we ignore Equipped items?
            //Uses LeGo functions: NPC_GetArmor, NPC_GetMeleeWeapon, NPC_GetRangedWeapon
            //Uses LeGo flag ITEM_ACTIVE_LEGO
            if ((NPC_GetArmor (slf) == itmInstance) || (NPC_GetMeleeWeapon (slf) == itmInstance) || (NPC_GetRangedWeapon (slf) == itmInstance) || (item.Flags & ITEM_ACTIVE_LEGO))
            && (transferEquippedItems == FALSE)
            {
                itmSlot = itmSlot + 1;
                MEM_StackPos.position = p;
            };
            
            //Should we ignore mission items ?
            if (item.Flags & ITEM_MISSION)
            && (transferMissionItems == FALSE)
            {
                itmSlot = itmSlot + 1;
                MEM_StackPos.position = p;
            };
                    
            //Transfer 1 by 1 (weapons, documents, and items without ITEM_MULTI flag)
            if ((invCategory == INV_WEAPON) && (item.MainFlag != ITEM_KAT_MUN))
            || (invCategory == INV_DOC)
            || !(item.Flags & ITEM_MULTI)
            {
                CreateInvItem (oth, itmInstance);
                NPC_RemoveInvItem (slf, itmInstance);
                
                //Something was transferred
                InventoryTransferred = TRUE;
            } else
            {
                itmCount = NPC_HasItems (slf, itmInstance);
                CreateInvItems (oth, itmInstance, itmCount);
                NPC_RemoveInvItems (slf, itmInstance, itmCount);
    
                //Something was transferred
                InventoryTransferred = TRUE;
            };
            
            MEM_StackPos.position = p;
        };    
    };
    
    /***
        Function will transfer all inventory categories from slf to oth.
        transferEquippedItems: FALSE will not transfer equipped items
        transferMissionItems: FALSE will not transfer mission items
    ***/
    FUNC VOID NPC_Transfer_Inventory (var int slfInstance, var int othInstance, var int transferEquippedItems, var int transferMissionItems)
    {
        var C_NPC slf;    
        slf = Hlp_GetNPC (slfInstance);
    
        var C_NPC oth;
        oth = Hlp_GetNPC (othInstance);
        
        //Reset by default
        InventoryTransferred = FALSE;
        
        NPC_Transfer_Inventory_Category (slf, oth, INV_WEAPON, transferEquippedItems, transferMissionItems);
        NPC_Transfer_Inventory_Category (slf, oth, INV_ARMOR, transferEquippedItems, transferMissionItems);
        NPC_Transfer_Inventory_Category (slf, oth, INV_RUNE, transferEquippedItems, transferMissionItems);
        NPC_Transfer_Inventory_Category (slf, oth, INV_MAGIC, transferEquippedItems, transferMissionItems);
        NPC_Transfer_Inventory_Category (slf, oth, INV_FOOD, transferEquippedItems, transferMissionItems);
        NPC_Transfer_Inventory_Category (slf, oth, INV_POTION, transferEquippedItems, transferMissionItems);
        NPC_Transfer_Inventory_Category (slf, oth, INV_DOC, transferEquippedItems, transferMissionItems);
        NPC_Transfer_Inventory_Category (slf, oth, INV_MISC, transferEquippedItems, transferMissionItems);
    };
    5. Dialog option for stealing
    Code:
    INSTANCE DIA_PickPocket (C_Info)
    {
        nr        = 998;                //Next to EXIT DIALOG which is usually 999
        condition    = DIA_PickPocket_Condition;
        information    = DIA_PickPocket_Info;
        permanent    = TRUE;
        description    = DIALOG_PICKPOCKET;
    };
    
    FUNC INT DIA_PickPocket_Condition ()
    {
        var string newDescription; newDescription = "";
        
        //If player already stole something .. exit
        if (self.aivar [AIV_MOD_PICKPOCKET] == cPickPocketed_Yes)
        {
            return FALSE;
        };
        
        //Adjust description. If victims (self) dexterity <= heros dexterity - add green color
        //You can find hook which controls color-changing of dialogs here:
        //https://forum.worldofplayers.de/forum/threads/1532719-G1-G2-Simple-dialogs-font-change-and-color-change?p=26016092&viewfull=1#post26016092
        if (self.attribute [ATR_DEXTERITY] <= hero.attribute [ATR_DEXTERITY])
        {
            newDescription = ConcatStrings ("c#00CC66 cs#66FFB2 ", DIALOG_PICKPOCKET);
        } else
        {
            //Otherwise add orange color and delta indicating how many dexterity points player needs to gain
            var int delta;
            delta = self.attribute [ATR_DEXTERITY] - hero.attribute [ATR_DEXTERITY];
            
            newDescription = ConcatStrings (DIALOG_PICKPOCKET, " ");
            newDescription = ConcatStrings (newDescription, IntToString (delta));
            
            newDescription = ConcatStrings ("c#FF8000 cs#FFB266 ", newDescription);
        };
        
        //Assign new description to dialog instance
        DIA_PickPocket.description = newDescription;
    
        //Check if this NPC can be pickpocketed
        if (self.ID == 538)    //Huno
        ...
        {
            return TRUE;
        };
        
        return FALSE;
    };
    
    FUNC VOID DIA_PickPocket_Info ()
    {
        if (self.attribute [ATR_DEXTERITY] > hero.attribute [ATR_DEXTERITY])
        {
            return;
        };
        
        //Remember self npc
        StealVictim = Hlp_GetNPC (self);
        
        //Exit_Dialog
        AI_StopProcessInfos (self);
    
    //---
        //Insert StealHelper to waypoint TOT if he is not already inserted
        //Make sure that each LEVEL has this waypoint available
        var oCNPC npc;
        npc = Hlp_GetNPC (StealHelper);
    
        if (!Hlp_IsValidNpc (npc)) {
            var C_NPC selfBackup;    //self is over-written by Wld_InsertNpc
            selfBackup = Hlp_GetNpc (self);
            
            Wld_InsertNpc (StealHelper, "TOT");
    
            npc = Hlp_GetNpc (StealHelper);
            self = Hlp_GetNpc (selfBackup);
        };
        
        //Transfer inventory from StealVictim to StealHelper
        NPC_Transfer_Inventory (StealVictim, StealHelper, FALSE, TRUE);
        
        //If there was not a single item transferred (modder should fix that ;)), create at least something
        if (InventoryTransferred == FALSE) {
            CreateInvItems (StealHelper, itmiNugget, 1);
        };    
    
        //Put hero into 'sleepingMode'
        var oCNPC her;
        her = Hlp_GetNPC (PC_Hero);
        her._zCVob_bitfield[2] = (her._zCVob_bitfield[2] & ~ zCVob_bitfield2_sleepingMode) | 0;
        
        //Change heros focus to StealHelper
        her.focus_vob = MEM_InstToPtr (npc);
        
        //Open dead NPC inventory
        NPC_OpenDeadNpc (hero);
        
        PickPocketing_Dialog = cPP_Dialog_Selected;
    };
    
    FUNC VOID B_AssignPickPocketDialog (var C_NPC slf)
    {
        //If player knows how to pickpocket, then run this dialog on each NPC
        if (vPT_PickPocketing == TRUE)    
        {
            DIA_PickPocket.npc = Hlp_GetInstanceID (slf);
        };
    };
    6. We need to assign our pickpocket dialog option to NPC in ZS_Talk:
    Code:
    func void ZS_Talk()
    {
    //---    Standard ZS_Talk_Loop stuff
        ...
        ...
        ...
        
    //---    Assign our dialog to each NPC
        B_AssignPickPocketDialog (self)
        
    //---    Standard ZS_Talk_Loop stuff
        B_AssignAmbientInfos (self);
        self.aivar [AIV_FINDABLE] = TRUE;
        AI_ProcessInfos (self);
    };
    7. If you read code above properly - DIA_PickPocket_Info executed command AI_StopProcessInfos. This will cause dialogs to disappear but also NPC you have been talking to will exit dialog and continue with its daily routine. We don't want that - that's why we have to adjust ZS_Talk_Loop:
    Code:
    FUNC INT ZS_Talk_Loop ()
    {
    //---    Standard ZS_Talk_Loop stuff
        if (C_BodyStateContains (self, BS_SIT))
        {
            if (self.aivar [AIV_HangAroundStatus] <= 2)
            {
                AI_LookAtNpc (self, hero);
            };
        };
        
    //---    Is our PickPocketing system active ? if yes - let NPC wait in a ZS_Talk_Loop
        if (PickPocketing_Dialog == cPP_Dialog_Selected)
        {
            return LOOP_CONTINUE;
        };
    
    //---    If Player stole something OR canceled his action ... we can restore dialog
        if (PickPocketing_Dialog == cPP_Dialog_Done)
        || (PickPocketing_Dialog == cPP_Dialog_Canceled)
        {
            //If player stole something
            if (PickPocketing_Dialog == cPP_Dialog_Done)
            {
                //Make sure that NPC will not be pickpocketed again
                self.aivar [AIV_MOD_PICKPOCKET] = cPickPocketed_Yes;
            };
    
            //PickPocketing system is 'closed' - default
            PickPocketing_Dialog = cPP_Dialog_Default;
    
            //Restore other - always hero
            other = Hlp_GetNPC (hero);
    
            //Remove AIV_INVINCIBLE flags ... so ZS_Talk can start again
            self.aivar[AIV_INVINCIBLE] = FALSE;
            other.aivar[AIV_INVINCIBLE] = FALSE;
    
            //Restore dialog
            AI_StartState (self, ZS_Talk, 1, "");
            
            return LOOP_END;
        };
    
    //---    Standard ZS_Talk_Loop stuff
        if (InfoManager_HasFinished ())
        {
            PrintDebugNpc (PD_ZS_Check, "...InfoManager beendet!");
    
            self.aivar[AIV_INVINCIBLE] = FALSE;
            other.aivar[AIV_INVINCIBLE] = FALSE;
    
            B_ResetFaceExpression (other);
            B_ResetFaceExpression (self);
    
            return LOOP_END;
        };
    
        return LOOP_CONTINUE;
    };
    8. And finally most important piece - hooks that will recognize, that player selected an item or closed the inventory and canceled action:
    Code:
    //Class definition cut out from Ikarus oCNPC class definition
    class oCNpcInventory {
                var int    inventory2_vtbl;                                      // 0x0550 1360
                var int    inventory2_oCItemContainer_contents;                        // 0x0554 zCListSort<oCItem>*
                var int    inventory2_oCItemContainer_npc;                             // 0x0558 oCNpc*
                var int    inventory2_oCItemContainer_selectedItem;                    // 0x055C int
                var int    inventory2_oCItemContainer_offset;                          // 0x0560 int
                var int    inventory2_oCItemContainer_drawItemMax;                     // 0x0564 int
                var int    inventory2_oCItemContainer_itemListMode;                    // 0x0568 oTItemListMode
                var int    inventory2_oCItemContainer_frame;                           // 0x056C zBOOL
                var int    inventory2_oCItemContainer_right;                           // 0x0570 zBOOL
                var int    inventory2_oCItemContainer_ownList;                         // 0x0574 zBOOL
                var int    inventory2_oCItemContainer_prepared;                        // 0x0578 zBOOL
                var int    inventory2_oCItemContainer_passive;                         // 0x057C zBOOL
                var int    inventory2_oCItemContainer_viewCat;                         // 0x0580 zCView*
                var int    inventory2_oCItemContainer_viewItem;                        // 0x0584 zCView*
                var int    inventory2_oCItemContainer_viewItemActive;                  // 0x0588 zCView*
                var int    inventory2_oCItemContainer_viewItemHightlighted;            // 0x058C zCView*
                var int    inventory2_oCItemContainer_viewItemActiveHighlighted;       // 0x0590 zCView*
                var int    inventory2_oCItemContainer_viewItemFocus;                   // 0x0594 zCView*
                var int    inventory2_oCItemContainer_viewItemActiveFocus;             // 0x0598 zCView*
                var int    inventory2_oCItemContainer_viewItemHightlightedFocus;       // 0x059C zCView*
                var int    inventory2_oCItemContainer_viewItemActiveHighlightedFocus;  // 0x05A0 zCView*
                var int    inventory2_oCItemContainer_viewItemInfo;                    // 0x05A4 zCView*
                var int    inventory2_oCItemContainer_viewItemInfoItem;                // 0x05A8 zCView*
                var int    inventory2_oCItemContainer_textView;                        // 0x05AC zCView*
                var int    inventory2_oCItemContainer_viewArrowAtTop;                  // 0x05B0 zCView*
                var int    inventory2_oCItemContainer_viewArrowAtBottom;               // 0x05B4 zCView*
                var int    inventory2_oCItemContainer_rndWorld;                        // 0x05B8 zCWorld*
                var int    inventory2_oCItemContainer_posx;                            // 0x05BC int
                var int    inventory2_oCItemContainer_posy;                            // 0x05C0 int
                var string inventory2_oCItemContainer_textCategoryStatic;              // 0x05C4 zstring
                var int    inventory2_oCItemContainer_m_bManipulateItemsDisabled;      // 0x05D8 zBOOL
                var int    inventory2_oCItemContainer_m_bCanTransferMoreThanOneItem;   // 0x05DC zBOOL
                var int    inventory2_oCItemContainer_image_chroma;                    // 0x05E0 zCOLOR
                var int    inventory2_oCItemContainer_blit_chroma;                     // 0x05E4 zCOLOR
    //      }
            var int        inventory2_owner;                           // 0x05E8 oCNpc*
            var int        inventory2_packAbility;                     // 0x05EC zBOOL
    //      zCListSort<oCItem>[INV_MAX] inventory {
                var int    inventory2_inventory0_Compare;              // 0x05F0 int(_cdecl*)(oCItem*,oCItem*)
                var int    inventory2_inventory0_data;                 // 0x05F4 oCItem*
                var int    inventory2_inventory0_next;                 // 0x05F8 zCListSort<oCItem>*
                var int    inventory2_inventory1_Compare;              // 0x05FC int(_cdecl*)(oCItem*,oCItem*)
                var int    inventory2_inventory1_data;                 // 0x0600 oCItem*
                var int    inventory2_inventory1_next;                 // 0x0604 zCListSort<oCItem>*
                var int    inventory2_inventory2_Compare;              // 0x0608 int(_cdecl*)(oCItem*,oCItem*)
                var int    inventory2_inventory2_data;                 // 0x060C oCItem*
                var int    inventory2_inventory2_next;                 // 0x0610 zCListSort<oCItem>*
                var int    inventory2_inventory3_Compare;              // 0x0614 int(_cdecl*)(oCItem*,oCItem*)
                var int    inventory2_inventory3_data;                 // 0x0618 oCItem*
                var int    inventory2_inventory3_next;                 // 0x061C zCListSort<oCItem>*
                var int    inventory2_inventory4_Compare;              // 0x0620 int(_cdecl*)(oCItem*,oCItem*)
                var int    inventory2_inventory4_data;                 // 0x0624 oCItem*
                var int    inventory2_inventory4_next;                 // 0x0628 zCListSort<oCItem>*
                var int    inventory2_inventory5_Compare;              // 0x062C int(_cdecl*)(oCItem*,oCItem*)
                var int    inventory2_inventory5_data;                 // 0x0630 oCItem*
                var int    inventory2_inventory5_next;                 // 0x0634 zCListSort<oCItem>*
                var int    inventory2_inventory6_Compare;              // 0x0638 int(_cdecl*)(oCItem*,oCItem*)
                var int    inventory2_inventory6_data;                 // 0x063C oCItem*
                var int    inventory2_inventory6_next;                 // 0x0640 zCListSort<oCItem>*
                var int    inventory2_inventory7_Compare;              // 0x0644 int(_cdecl*)(oCItem*,oCItem*)
                var int    inventory2_inventory7_data;                 // 0x0648 oCItem*
                var int    inventory2_inventory7_next;                 // 0x064C zCListSort<oCItem>*
                var int    inventory2_inventory8_Compare;              // 0x0650 int(_cdecl*)(oCItem*,oCItem*)
                var int    inventory2_inventory8_data;                 // 0x0654 oCItem*
                var int    inventory2_inventory8_next;                 // 0x0658 zCListSort<oCItem>*
    //      }
            var string     inventory2_packstring;                      // 0x065C zstring[INV_MAX]
            var string     inventory2_packstring1;
            var string     inventory2_packstring2;
            var string     inventory2_packstring3;
            var string     inventory2_packstring4;
            var string     inventory2_packstring5;
            var string     inventory2_packstring6;
            var string     inventory2_packstring7;
            var string     inventory2_packstring8;
            var int        inventory2__offset[9];                      // 0x0710 int[INV_MAX]
            var int        inventory2__itemnr[9];                      // 0x0734 int[INV_MAX]
            var int        inventory2_maxSlots[9];                     // 0x0758 int[INV_MAX]
            var int        inventory2_invnr;                           // 0x077C int
    };
    
    //Already available in LeGo package
    //const int oCNpc__CloseInventory                     = 7058164;
    
    //This function is called when player closes inventory
    FUNC VOID _HOOK_NPC_CLOSEINVENTORY ()
    {
        var oCNPC npc;
        npc = _^(ECX);
        
        //Is this player?
        if (NPC_IsPlayer (npc))
        {
            //Is player in pickpocketing dialog?
            if (PickPocketing_Dialog == cPP_Dialog_Selected)
            {
                //'Cancel' pickpocketing dialog
                PickPocketing_Dialog = cPP_Dialog_Canceled;
                
                //Remove StealHelper from focus_vob
                npc.focus_vob = 0;
                
                //Remove hero from 'sleepingMode'
                npc._zCVob_bitfield[2] = (npc._zCVob_bitfield[2] & ~ zCVob_bitfield2_sleepingMode) | 1;
                
                //Transfer inventory from StealHelper back to StealVictim
                NPC_Transfer_Inventory (StealHelper, StealVictim, FALSE, TRUE);
            };
        };
    };
    
    //00669780  .text     Debug data           ?TransferItem@oCItemContainer@@MAEHHH\@Z
    const int oCItemContainer__TransferItem = 6723456;
    
    //This function is called when player transfers an item
    FUNC VOID _HOOK_ITEMCONTAINER_TRANSFERITEM ()
    {
        var oCNpcInventory npcInventory;
        var C_NPC npc;
        var oCItem itm;
        var int amount;
        var int itmInstance;
        var oCNPC her;
    
        //Are we in pickpocketing mode?
        if (PickPocketing_Dialog == cPP_Dialog_Selected)
        {
            //PickPocketing_Dialog done - ZS_Talk will take care of setting aivar AIV_MOD_PICKPOCKET
            PickPocketing_Dialog = cPP_Dialog_Done;
    
            //int __thiscall oCItemContainer::TransferItem(int,int)
            
            //ECX        8245076 -> oCNpcContainer, oCNpcInventory works though ;-P
            //ESP + 4    ?
            //ESP + 8    quantity
    
            npcInventory = _^(ECX);
            
            //Get inventory owner
            npc = _^(npcInventory.inventory2_owner);
    
            //What item player selected?
            itm = _^(List_GetS(npcInventory.inventory2_oCItemContainer_contents, npcInventory.inventory2_oCItemContainer_selectedItem + 2));
            
            //Get amount
            amount = itm.amount;
            
            //Get item instance
            itmInstance = Hlp_GetInstanceID (itm);
    /*
            //Limit no of items that can be stolen to 100
            if (amount > 100)
            {
                amount = 100;
            };
    */        
            //Create selected item * amount in players inventory
            CreateInvItems (hero, itmInstance, amount);
            
            //Remove item * amount from npc
            NPC_RemoveInvItems (npc, itmInstance, amount);
    
            //Write 0 to ESP + 8 - don't transfer anything using this engine function
            MEM_WriteInt (ESP + 8, 0);
                    
            //Remove StealHelper from focus_vob
            her = Hlp_GetNPC (PC_Hero);        
            her.focus_vob = 0;
    
            //Remove hero from 'sleepingMode'
            her._zCVob_bitfield[2] = (her._zCVob_bitfield[2] & ~ zCVob_bitfield2_sleepingMode) | 1;
            
            //Close inventory
            CALL__thiscall (MEM_InstToPtr (npcInventory), oCNpcInventory__Close);
    
            //Transfer inventory from StealHelper back to StealVictim
            NPC_Transfer_Inventory (StealHelper, StealVictim, FALSE, TRUE);
    
            //Add XP
            vPT_PickPocketing_Counter = vPT_PickPocketing_Counter + 1;
    
            MEM_PushIntParam (vPT_PickPocketing_Counter * XP_Bonus_PickPocketing);
            MEM_Call (B_GiveXP);         
        };
    };
    9. Hook it with:
    Code:
        HookEngine (oCNPC__CloseInventory, 6, "_HOOK_NPC_CLOSEINVENTORY");
        HookEngine (oCItemContainer__TransferItem, 5, "_HOOK_ITEMCONTAINER_TRANSFERITEM");
    And that should be it - hopefully I didn't forget any piece of code
    Geändert von F a w k e s (22.06.2019 um 15:16 Uhr)

  8. Beiträge anzeigen #8 Zitieren
    Apprentice
    Registriert seit
    Feb 2018
    Beiträge
    19
     
    bogu9821 ist offline
    Zitat Zitat von Noxum Beitrag anzeigen
    Der Punkt 2 ist mir noch nicht ganz klar. Woran hängt die Erfolgschance des Diebstahls ab? In Gothic 2 gibt es dazu eine Mapping Liste (Dex 10-20 ein Kinderspiel, Dex 21 - 40 einfach, usw.). In Gothic 1 in der Charakterübersicht gibt es eine prozentuale Angabe (z.B. 10%).
    Unschön wäre, wenn die Logik wirklich nur auf Basis von Taschendiebstahl Stufe 1 und 2 "würfelt", ob ein Diebstahl erfolgreich ist oder nicht. Eine Erhöhung der prozentualen Werte wäre ein Anfang.

    Was denkt ihr zum Thema?
    Ist der Taschendiebstahl in Gothic 1 noch zu retten, sofern man diesen verbessert und eine chronische Geldknappheit (über den ganzen Spielverlauf hinweg) schafft?

    Noxum
    The chance of success in Pocket Theft is calculated based on whether the (pseudo)random number between 0 and 99 is less than the Talent of pickpocketing.
    You can set this talent value with:
    Code:
     Npc_SetTalentSkill (slf, 6, X);
    If you want to rewrite theft system, you need to know the lego or Union package well.
    Geändert von bogu9821 (22.06.2019 um 15:27 Uhr)

  9. Beiträge anzeigen #9 Zitieren
    Krieger Avatar von Noxum
    Registriert seit
    Sep 2006
    Ort
    Worms
    Beiträge
    453
     
    Noxum ist offline
    Zitat Zitat von F a w k e s Beitrag anzeigen
    Hi Noxum,
    I have implemented in my G1 modification a different method of Pickpocketing - hybrid of both worlds G1 & G2A.
    Hi Fawkes,
    that you're sharing your solution is really appreciated and it's way better than the original thief system
    Also you are right, the punishment approach is no well solution since we'll all doing the save/reload thing.

    The only point I don't like too much is the fact that the player is stealing by dialog. It's a bit clinical, without emotions or earmarked.
    It has a certain charm when sneaking behind a NCP and stealing stuff without being seen by others. Still a level of thrill (if you get caught by other NPC's you still get the punish) so you have to study the victims daily routine or maybe it's not feasible at all (e.g. Thorus). Additionally, if you do not have enough dex to steal it is prompted on the screen, for example "Pickpocketing not possible, +13 dexterity needed", something like that.

    Cheers,
    Noxum

  10. Beiträge anzeigen #10 Zitieren
    Hero Avatar von lali
    Registriert seit
    Feb 2016
    Beiträge
    5.473
     
    lali ist offline
    While appreciating all the endeavour in Fawkes solution, I do not like it either, that its happening in a dialogue. Sneaking and actually visualized stealing instead of just a dialogue would be #1 for me to build up upon to improve the system. Also I think the punishment needs to be there. With the dialogue system it might be unnecessary, but if you do it stealth-wise there needs to be the possibility to get caught. I also do not think that its a good solution to have a print saying you need more dexterity to even try it. Why shouldn't you be able to try it always? The more aware this npc is, maybe depending on his level, the harder it is and your dexterity might be the limiting factor in this, but no need to prevent the player from trying it beforehand.

    Ich würde sagen, alle deine Punkte im EP sind richtig.

    (1) Nicht nur namenlose NPCs sollte man bestehlen können. Ich würde sagen, damit das Taschendiebstahl-System in Gothic 1 Sinn macht, sollten die stehlbaren Items bei jedem NPC genauso von Hand gesetzt sein wie das Inventar selbst. Also, es gibt diese und jene Items im Inventar, und irgendwie sagt man: Von diesen Items kann dieses und jenes gestohlen werden. Bei namenlosen NPCs kann man da natürlich einen gewissen Zufall hereinbringen, aber ansonsten würde ich es von Hand setzen.

    (2) Zu "er eh immer fehlschlägt" kann ich nichts sagen. Ich habe keine Ahnung, wie das berechnet wird, aber wenn das so ist, ist das sicher ein wichtiger Punkt.

    (3) Er kostet nicht zu viele LP, wenn man deinen Punkt 3 löst, laut dem er sich nicht lohnt. Würde er sich lohnen, z.B. auch durch Erfahrungspunkte zumindest bei NPCs mit Namen oder etwa durch Geschick-Boni unter gewissen Bedingungen etc., dann wären auch die LP Kosten gerechtfertigt.

    (4) Da es mehrere Stufen gibt, sollte das auch irgendeinen Einfluss darauf haben, was man damit so machen kann, vielleicht auch wie es visualisiert wird, wie bei den Kampftalenten (neue Animationen etc.). Zum Beispiel könnte Stufe 1 das Stehlen auf schlafende oder sonstwie stark abgelenkte NPCs beschränken und Stufe 2 würde es für die restlichen freischalten. Es könnte Einfluss darauf haben, wie leicht man dabei entdeckt wird (ich weiß nicht, welchen Einfluss es immoment überhaupt hat). Oder Stufe 2 würde das Schleichen nicht mehr zur Voraussetzung machen, sondern man könnte es im normalen Gehen unternehmen, jemanden am hellichten Tag zu bestehlen, an dem man gerade eng vorbeiläuft.

    (5) Zuletzt empfinde ich es am wichtigsten, dass man den Taschendiebstahl insofern in die Story einbaut, als dass er in manchen Situationen nötig ist je nach Gilde oder alternative Lösungsmöglichkeiten für Quests ermöglicht. Wirklich verbessert und sinnvoll gemacht ist so ein System ja erst dann, wenn es auch ins Spiel eingebunden ist. Wenn dus im Laufe der Story nie machen musst und es sich nicht anbietet, machst dus auch nicht. Aber das ist dann weniger eine Frage der Verbesserung dieses Systems an sich, als des allgemeinen Designs, wie man Quests aufbaut oder erweitert und so.
    Phoenix Dev | Website | Discord

  11. Beiträge anzeigen #11 Zitieren
    Krieger Avatar von Noxum
    Registriert seit
    Sep 2006
    Ort
    Worms
    Beiträge
    453
     
    Noxum ist offline
    But what do you say against the fact, that everyone - or almost everyone - of us will load the savegames just before the steal failed and try it again, and again,and again... and okay that's annoying but I've to do in order to gain gold/ore -> no fun or?

    And that's unfortunately the case.

    How is it implemented in other games?

  12. Beiträge anzeigen #12 Zitieren
    Hero Avatar von lali
    Registriert seit
    Feb 2016
    Beiträge
    5.473
     
    lali ist offline
    But you guys do the same before trying to open a chest, so you loose no single picklock in the entire game. You do it before sneaking into a house and load again if you get caught. Some do even save before every fight and load again if they get damage they could have avoided. They also save before important dialogues and when the outcome of their choices is not what they expected or wanted it to be, they load again.

    I do not like this either, but it is the case in every other game too, even in the best stealth games, IF and as long as you are allowed to save wherever you want. The only way to force the player to be more careful with his choices and to accept the consequences of their actions is to limit the possibility to save and have specific save points. In my experience from earlier discussions most of the players here do not like this. I would like to play like this a lot more. For example, saving only at bookstands which are distributed at specific (save) locations in the world. Not in the wilderness of course, so that sayings like "Geh niemals allein in den Wald!" are making sense then. The game is trying to give the player a sense of danger, and you felt this maybe the first few times you played. But since every Gothic player is saving every few minutes at least, there is nothing left of this. Specific save points, in my opinion, would do the game and its intrinsic design a favour, just like (the once planned) limited inventory would do. I spoke about the latter in length in other posts already. In our mods we want to realize both. The inventory will be obligatory, because the balancing needs to be adjusted for it and wouldn't work without. The save spots propably not. But I like the idea a lot.

    Doesn't mean that there are no other possibilities for a solution without limiting the save games, but I know none which wouldn't require huge changes to realize consequences in every aspect of the game, who might be rewarding for the player to live through, or a resurrection system if you die (this was also an idea in the early concept stage). I prefer my solution.
    Phoenix Dev | Website | Discord
    Geändert von lali (05.07.2019 um 19:00 Uhr)

  13. Beiträge anzeigen #13 Zitieren
    Alter Medizinmann Avatar von Tentarr
    Registriert seit
    May 2016
    Beiträge
    17.604
     
    Tentarr ist offline
    Ich mag deine Idee Lali und finde sie wäre für Gothic genau auf die Punkte die du ansprichst die richtige gewesen

  14. Beiträge anzeigen #14 Zitieren
    Schwertmeister Avatar von Inspirate
    Registriert seit
    Aug 2012
    Beiträge
    959
     
    Inspirate ist offline
    Seinerzeit habe ich mal Thiel Hater eine geänderte Version der Welt der Verurteilten überlassen in der zum einem das Diebstahlsystem aus G1 und ab gemeisterter Stufe das Diebstahlsystem aus G2 zum Einsatz kommt wo dann auch Personen wie Gomez (wenn genügend Geschick da ist) beklaut werden können. Insgesamt sind dadurch ca. 140 NPCs im Spiel mehr zu beklauen mit teilweise recht guter Beute wie z.B. Stärketrank oder ähnliches.

    Der link dazu ist hier zu finden. >>KLICK MICH<<

  15. Beiträge anzeigen #15 Zitieren
    Alter Medizinmann Avatar von Tentarr
    Registriert seit
    May 2016
    Beiträge
    17.604
     
    Tentarr ist offline
    Das ist ja interessant, kann man die immer noch so herunterladen und nutzen?

  16. Beiträge anzeigen #16 Zitieren
    Schwertmeister Avatar von Inspirate
    Registriert seit
    Aug 2012
    Beiträge
    959
     
    Inspirate ist offline
    Zitat Zitat von Tentarr Beitrag anzeigen
    Das ist ja interessant, kann man die immer noch so herunterladen und nutzen?
    Ja, das geht. Es waren aber (soweit ich mich erinnern kann) kleinere Fehler beim Bestehlen von Baals drin. Bei Baals ging der Diebstahl immer schief und sie griffen an.

    Aber der eigentliche gescriptete Endstand war dann auch nicht diese Version. Im stillen Kämmerlein hatte ich diese Version noch vorangetrieben und die Diebstahlfehler behoben, die Mine am Eingang zugänglich gemacht, Schildkampf und Helme eingebaut, variablen Waffenschaden und den englischen Unpatch (übersetzt) mit eingebaut als auch ein verändertes Kostensystem aus der GothicTime 4.0. Da habe ich aber alle scripte von auf einer alten Sicherungsplatte im Schrank liegen. Könnte ich mal bei Gelegenheit raussuchen. Darf aber wegen (Sequelinhalt) nicht weitergegeben werden. Aber unter der Hand?

    [Bild: eWdV.jpg]

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