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

 

Results 1 to 14 of 14
  1. Visit Homepage View Forum Posts #1 Reply With Quote
    Exodus Sektenspinner's Avatar
    Join Date
    Jul 2004
    Location
    Karlsruhe
    Posts
    7,827
     
    Sektenspinner is offline

    [Script] Broadcasts

    Wichtig: Für Ikarus Nutzer gibt es eine überarbeitete Version, die der in diesem Post vorgestellten Version vorzuziehen ist.

    Es gibt Fälle, in denen man Nachrichten innerhalb der KI-Glocke verbreiten möchte. Das könnte sein:
    • Nachricht: Es ist eine Sekunde Zeit vergangen.
    • Nachricht: Es wurden Zauber xy von Npc yz gesprochen.
    • Nachricht: Alle Freunde / Feinde von Npc yz sollen gezählt werden.
    • [...]


    Ich nutze das System exzessiv für selektive und nicht selektive Schlachtfeldzauber. Außerdem gehe ich jede Sekunde durch jeden Npc in der KI-Glocke um eventuelle zeitverzögerte Effekte abzuhandeln.

    Bis gestern habe ich dafür mein ForAllNpcs-System genutzt, das aber dem neuen, besseren System weichen musste.

    Da ich es für praktisch halte, möchte ich es hier vorstellen.

    Code:
    /*######################################################
    //
    //	Broadcast Dokumentation
    //
    //######################################################
    
    //--------------------------------------
    // Idee
    //--------------------------------------
    
    In manchen Fällen möchte man, dass eine ganze Reihe von Npcs
    von einem Ereignis in Kenntnis gesetzt werden. Zum Beispiel
    könnte ein Massenheilzauber gesprochen worden sein, sodass alle
    Npcs auf dem Schlachtfeld volles Leben bekommen sollen.
    
    Man könnte sagen, der Zauberer (caster) verbreitet
    (broadcastet) die Nachricht "Massenheilung".
    
    In solchen und ähnlichen Fällen liefern diese Scripte eine
    elegante und leicht zu handhabende Lösung.
    
    //--------------------------------------
    // Grundlegende Funktionsweise
    //--------------------------------------
    
    Das Broadcastsystem verwaltet eine Liste von Npcs. Zu dieser
    Liste müssen aktiv Npcs hinzufügt werden, wenn dies gewünscht ist,
    zum Beispiel, wenn ein Npc die KI-Glocke betritt.
    Das Broadcastsystem löscht selbstständig Npcs aus der Liste,
    wenn eine vom Benutzer spezifizierte Bedingung erfüllt ist.
    Diese Bedingung könnte sein dass der Npc aus der KI-Glocke
    verschwunden ist.
    
    Es ist jederzeit möglich einen sogenannten Broadcast durchzuführen,
    wobei ein caster (der den Broadcast "ausspricht") und eine Nachricht
    (das "was" der Broadcaster ausspricht) angegeben werden.
    
    Dies führt dann dazu, dass für alle Npcs, die sich zu dem Zeitpunkt
    in der Liste befinden, die Funktion B_AssessBroadcast aufgerufen wird.
    Dort kann jeder Npc für sich entscheiden, wie er mit dem Broadcast
    umgehen möchte. Dabei hat er Zugriff auf den caster und die Nachricht.
    
    //--------------------------------------
    // Was ist zu beachten?
    //--------------------------------------
    
    -~- Die Scripte nutzen die CallByString Routine aus der
    Schleifenimplementierung. Diese gibt es hier:
    http://forum.worldofplayers.de/forum/showthread.php?t=691617
    
    -~- Eine Funktion nutzt zudem Nicos oCNpcs. Diese gibt es hier:
    http://forum.worldofplayers.com/forum/showthread.php?t=635427
    
    -~- BroadCasts.d kann sehr früh geparst werden, allerdings nach
    den eben genannten, notwendigen Scripten.
    
    -~- B_AssessBroadCast.d kann und sollte spät geparst werden.
    Nur dann kann deine Behandlung der Broadcasts auf die üblichen
    Funktionen von Gothic zugreifen.
    
    -~- Der in BC_FARFARAWAY eingetrage WP muss existieren.
    Standardmäßig enthält diese Stringkonstante den Wert "TOT".
    
    -~- Wenn Npcs in der KI-Glocke gesammelt werden sollen, muss in
    der Funktion "B_RefreshAtInsert" der Funktionsaufruf
    "RegisterNpc (self);" eingefügt werden. Ist dies geschehen
    ist das System funktionstüchtig.
    
    -~- Das System kann angepasst werden, sodass nicht nach Npcs
    in der KI-Glocke gesucht werden, sondern ein anderes Kriterium
    verwendet wird.
    
    -~- Wenn der Parameter messageID nicht gebraucht wird, muss man
    ihn natürlich nicht sinnvoll befüllen.
    
    //--------------------------------------
    // Das Interface und seine Benutzung
    //------------------------------------*/
    
    /* Leere die verwaltete Liste von Npcs */
    void BC_ClearList()
    
    /* Prüfe, ob slf in der Liste vorhanden ist */
    int BC_IsInList(C_NPC slf)
    
    /* Füge einen Npc in die Liste hinzu. Beachte: Wenn ein Npc bereits
     * in der Liste ist oder einer bestimmten Ausnahmebedingung genügt,
     * wird er nicht hinzugefügt. Dies kann jedoch angepasst werden
     * (siehe unten: DontRegisterThisNpc und BC_ALLOW_DUPLICATES). */
    void RegisterNpc(C_NPC slf)
    
    /* Caster verbreitet die Nachricht messageID an die Liste.
     * Das heißt: Für jeden Npc slf (inklusive dem caster selbst),
     * der in der Liste enthalten ist, wird aufgerufen:
     * B_AssessBroadcast(slf, caster, messageID)
     *
     * Vor dem erste Broadcast wird zudem:
     * B_BeforeFirstBroadCast(caster, messageID);
     * aufgerufen und nach dem letzten Broadcast:
     * B_AfterLastBroadCast(caster, messageID);
     */
    void Broadcast(C_NPC caster, int messageID)
    
    /* Wie Broadcast, mit der Ausnahme, dass der caster sich nicht niemals
     * selbst benachrichtigt, selbst wenn er in der Liste steht.
     * Man merke sich "Ex" als "Exklusiv dem Caster" */
    void BroadcastEx(C_NPC caster, int messageID)
    
    //--------------------------------------
    // Konfigurierbare Funktionen
    // und Variablen
    //--------------------------------------
    
    /* Wenn RegisterNpc auf einem Npc aufgerufen wird, wird dieser
     * nicht sofort zur Liste hinzugefügt. Zuvor wird diese Funktion
     * befragt, ob der Npc auf WIRKLICH registriert werden soll.
     * Zwei Ausnahmen, in denen die Registrierung abgebrochen werden soll,
     * sind in der Funktion bereits implementiert. */
    int DontRegisterThisNpc (C_NPC slf)
    
    /* Das Broadcastsystem wirft selbstständig Npcs aus der Liste heraus,
     * wenn DontKeepThisNpc dies so vorsieht. Vorimplementiert ist, dass Npcs,
     * die sich nicht in der KI-Glocke befinden aus der Liste gestrichen werden.
     * Es sind aber Anwendungen denkbar, in denen das nicht beabsichtigt ist.
     * In dem Fall, muss diese Funktion abgeändert werden. */
    int DontKeepThisNpc (C_NPC slf)
    
    /* In der Standardkonfiguration erlaubt das Broadcastsystem nicht,
     * dass ein Npc doppelt in der Liste auftaucht. Dies kann aber verändert
     * werden, sodass jeder Aufruf von RegisterNpc(npc) zu einem weiteren Eintrag
     * in der Liste führt. Dann erhält der npc eine über Broadcast verbreitete
     * Nachricht mehrfach. */
    const int BC_ALLOW_DUPLICATES = 0
    
    /* Da der Spieler oftmals einen Sonderfall darstellt, und es daher leicht
     * vergessen wird, ihn mit RegisterNpc in die Liste aufzunehmen, ist der Spieler
     * standardmäßig in der Liste vorhanden. Dies kann deaktiviert werden.
     * In diesem Fall wird der Spieler wie jeder andere Npc behandelt. */
    const int BC_PLAYER_ALWAYS_IN_LIST = 1
    Download der Scripte und der Dokumentation.

    Fragen, Anmerkungen und Fehlerberichte sind natürlich wie immer willkommen.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts
    Last edited by Sektenspinner; 18.09.2011 at 23:21.

  2. View Forum Posts #2 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,172
     
    Lehona is offline
    DontRegisterThisNpc() ist eine int Funktion (Das hat mir einiges zum Rätseln bzgl. des Inhaltes gegeben >.<), aber ansonsten sehe ich nichts, was es zu kritisieren gibt. Klasse gemacht!

  3. Visit Homepage View Forum Posts #3 Reply With Quote
    Exodus Sektenspinner's Avatar
    Join Date
    Jul 2004
    Location
    Karlsruhe
    Posts
    7,827
     
    Sektenspinner is offline
    Quote Originally Posted by Lehona View Post
    DontRegisterThisNpc() ist eine int Funktion
    Danke. Doku ist gefixt.

    aber ansonsten sehe ich nichts, was es zu kritisieren gibt.
    Hoffen wir mal, dass sonst alles stimmt.
    Wenn nicht, nur her mit den Fehlern.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  4. View Forum Posts #4 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,172
     
    Lehona is offline
    Ich werd's testen, bin gerade dabei einen vernünftigen EventHandler zu schreiben.
    Da muss ich auch gleich mal um Input bitten, momentan habe ich folgende Events:

    UnitTakesDamage
    AnyUnitTakesDamage

    UnitTakesMagicDamage
    AnyUnitTakesMagicDamage

    PeriodEvent
    TimerEvent

    UnitComesInRange //Bin mir noch nicht sicher, ob ich das evtl. nicht auslasse, ist sehr performance Aufwendig
    AnyUnitComesInRange

  5. Visit Homepage View Forum Posts #5 Reply With Quote
    Exodus Sektenspinner's Avatar
    Join Date
    Jul 2004
    Location
    Karlsruhe
    Posts
    7,827
     
    Sektenspinner is offline
    Quote Originally Posted by Lehona
    Da muss ich auch gleich mal um Input bitten
    Versteh nicht ganz was dein EventHandler tun soll.

    "UnitTakesDamage" klingt, als wäre das mehr oder minder B_AssessDamage und UnitComesInRange klingt nach B_RefreshAtInsert.

    Welche Ereignisse willst du wie behandeln und wofür soll man das zum Beispiel brauchen können?
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  6. View Forum Posts #6 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,172
     
    Lehona is offline
    Ein EventHandler halt... Aber egal, ich arbeite einfach erstmal alles aus, was ich bis jetzt habe, das wird sich dann wohl erklären (Ja, einige sind einfach zu implementieren wie z.b. das Damage-Event. Aber wenn ich einige andere, schwieriger anbiete, bau ich die dann doch gleich mit ein).

  7. Visit Homepage View Forum Posts #7 Reply With Quote
    Exodus Sektenspinner's Avatar
    Join Date
    Jul 2004
    Location
    Karlsruhe
    Posts
    7,827
     
    Sektenspinner is offline

    Ikarus Version der Broadcasts

    Ich hab eine Ikarus-Version der Broadcasts geschrieben. Diese ist bequemer zu benutzen und eleganter implementiert. Altes und neues System sind NICHT kompatibel.

    Hier sei zunächst ein Beispiel vorweggenommen, dass die Funktionsweise illustriert.

    Code:
    //************************************************
    //   Bestimme Anzahl der Freunde eines Npcs
    //   die gerade in der KI-Glocke sind.
    //************************************************
    
    var int friendsOfTheNpc; /* Hilfsvariable */
    
    /* Um diese Funktion geht es: */
    func int CountFriends(var C_NPC theNpc) {
        friendsOfTheNpc = 0;
        Broadcast(theNpc, CountFrieds_Sub); //unser Npc startet Broadcast
        return friendsOfTheNpc;
    };
    
    /* Hilfsfunktion. In slf landen nach und nach die verschiedenen
     * Npcs in der KI-Glocke. theNpc ist jedes mal derselbe. */
    func void CountFrieds_Sub(var C_NPC slf, var C_NPC theNpc) {
        /* Ist slf ein Freund von unserem Npc? */
        if (Npc_GetPermAttitude(slf, theNpc) == ATT_FRIENDLY) {
            friendsOfTheNpc += 1;
        };
    };
    Nun folgt der Code samt kurzer Dokumentation:

    Code:
    //#################################################
    //
    //    Nutzungshinweise:
    //
    //#################################################
    
    /*************************************************
    //   Idee
    //************************************************
    
    Die hier vorgestellten Funktionen ermöglichen es,
    für alle Npcs in der Welt oder alle Npcs in der KI-Glocke
    eine beliebige Funktion aufzurufen. 
    
    //************************************************
    //   Setup
    //************************************************
    
    Eine aktuelle Version von Ikarus wird benötigt.
    Ikarus gibt es hier:
    http://forum.worldofplayers.de/forum/threads/969446-Skriptpaket-Ikarus-3
    
    Die Datei, die du grade liest, ist nach Ikarus zu parsen.
     
    //************************************************
    //   Funktionen
    //************************************************
    
    func void DoForAll    (var func function)
    func void DoForSphere (var func function)
     
    "function" muss eine Funktion sein, die einen Parameter
    vom Typ C_NPC nimmt und nichts zurückgibt.
    DoForAll ruft function für jeden Npc auf, der in der Welt existiert.
    DoForSphere ruft function für jeden Npc in der KI-Glocke auf
    (also im Radius von ~40 Meter um die Kamera)
    
    Beispiel:
    
    **************************
    func void foo() {
        DoForSphere(SayHi);
    };
    
    func void SayHi(var C_NPC slf) {
        PrintDebug(ConcatStrings (slf.name, " sagt Hallo!"));
    };
    **************************
    
    Eine mögliche Anwendung für DoForAll wäre ein Schwierigkeitsgradsystem, dass,
    wenn der Schwierigkeitsgrad verändert wird, alle Npcs anpassen muss.
    
    ######### Broadcasts #########
    
    Eine einfache Abwandlung dieser Funktionen ist der Broadcast.
    Die Idee ist hierbei, dass ein Npc, der "Caster", eine Nachricht
    an alle anderen Npcs sendet, die dann bei jedem Npc verarbeitet wird.
    
    Beispielsweise könnte ein Npc, der einen Massenheilzauber spricht,
    dies "broadcasten" und die Npcs reagieren darauf, indem sie ihre Lebensenergie
    auffüllen (wenn sie in der selben Partei kämpfen wie der Caster).
    Grundsätzlich ergeben sich durch Broadcasts mannigfache Möglichkeiten für Flächenzauber.
    
    Broadcasts können auch Wahrnehmungen sinnvoll ergänzen und helfen eine Situation zu überblicken.
    Etwa könnte ein Monster, bevor es den Spieler angreift erstmal einen "durchzählen!"-Broadcast
    herausschicken, indem sich alle Freunde des Monsters "melden". So könnte ein Wolf,
    der alleine ist, fliehen (vielleicht sogar zu einem Rudel in der Nähe);
    ein Wolf, der im Rudel steht dagegen mutiger sein.
    
    Ein Troll, der den Spieler kommen sieht, könnte das allen Npcs mitteilen,
    woraufhin vielleicht Goblins in der Umgebung bei ihm Schutz suchen.
    
    Doch nun zur Funktion:
    
    func void Broadcast (var C_NPC caster, var func function)
    
    function muss eine Funktion sein, die zwei C_NPC Parameter entgegennimmt und nichts zurückgibt.
    Dann wird function(npc, caster) für jeden Npc aufgerufen, der folgende Bedingungen erfüllt:
    
    1.) Er ist in der KI-Glocke
    2.) Er ist nicht tot (HP != 0).
    
    Es gibt eine erweiterte ("EXtended") Version von Broadcast mit folgender Signatur:
    
    func void BroadcastEx(var C_NPC caster, var func function,
                          var int excludeCaster, var int includeDead, var int includeShrinked)
                          
    Sind die drei zusätzlichen Parameter 0, so verhält sich BroadcastEx genau wie Broadcast.
    Ansonsten beeinflussen die drei Parameter folgendes, wenn sie nicht Null sind:
    
        excludeCaster:   function wird nicht für den Caster aufgerufen
                         (das heißt der Caster benachrichtigt sich nicht selbst)
        includeDead:     Auch tote Npcs werden benachrichtigt (Bedingung 2. wird also ignoriert)
        includeShrinked: Auch Npcs außerhalb der KI-Glocke (die daher nur in einer abgespeckten
                         Version in der Welt existieren (kein aktives Visual)) werden benachrichtigt.
                         (das heißt Bedingung 1. wird ignoriert).
    
    Beispiel:
    
    **************************
    
    var int friendCount;
    //Gibt Anzahl Freunde von slf zurück, die in der KI-Glocke sind.
    func int CountFriends(var C_NPC slf) {
        friendCount = 0;
        Broadcast(slf, CountFrieds_Sub);
        return friendCount;
    };
    
    //Hilfsfunktion:
    func void CountFrieds_Sub(var C_NPC slf, var C_NPC caster) {
        if (Npc_GetPermAttitude(slf, caster) == ATT_FRIENDLY) {
            friendCount += 1;
        };
    };
    
    **************************
    
    Anmerkung: Schachteln der Funktionen ist nicht erlaubt.
    Das heißt während eine Ausführung von DoForAll / DoForSphere läuft,
    darf keine weitere gestartet werden.
    */
    
    //#################################################
    //
    //    Implementierung
    //
    //#################################################
    
    //************************************************
    //   The Core: Iterating through Lists.
    //************************************************
    
    func void _BC_ForAll(var int funcID, var int sphereOnly) {
        MEM_InitAll(); //safety, don't know if user did it.
    
        var int busy;
        if (busy) {
            MEM_Error("Broadcast-System: Nesting is not allowed!");
            return;
        };
        
        busy = true;
        
        var C_NPC slfBak; slfBak = Hlp_GetNpc(self);
        var C_NPC othBak; othBak = Hlp_GetNpc(other);
        
        if (sphereOnly) {
            /* to speed things up (and do the filtering)
             * we only search the (small) active Vob List */
            var int i;    i    = 0;
            var int loop; loop = MEM_StackPos.position;
            
            if (i < MEM_World.activeVobList_numInArray) {
                var int vob;
                vob = MEM_ReadIntArray(MEM_World.activeVobList_array, i);
                
                if (Hlp_Is_oCNpc(vob)) {
                    var C_NPC npc;
                    npc = MEM_PtrToInst(vob);
                    MEM_PushInstParam(npc);
                    MEM_CallByID(funcID);
                };
                
                i += 1;
                MEM_StackPos.position = loop;
            };
        } else {
            /* walk through the entire Npc List (possibly large). */
            var int listPtr; listPtr = MEM_World.voblist_npcs;
            loop = MEM_StackPos.position;
            
            if (listPtr) {
                vob = MEM_ReadInt(listPtr + 4);
                
                if (Hlp_Is_oCNpc(vob)) {
                    npc = MEM_PtrToInst(vob);
                    MEM_PushInstParam(npc);
                    MEM_CallByID(funcID);
                };
                
                listPtr = MEM_ReadInt(listPtr + 8);
                MEM_StackPos.position = loop;
            };
        };
        
        self  = Hlp_GetNpc(slfbak);
        other = Hlp_GetNpc(othbak);
        
        busy = false;
    };
    
    func void DoForAll    (var func _) {
        var MEMINT_HelperClass symb;
        var int theHandlerInt;
        theHandlerInt = MEM_ReadInt(MEM_ReadIntArray(contentSymbolTableAddress, symb - 1) + zCParSymbol_content_offset);
    
        _BC_ForAll(theHandlerInt, 0);
    };
    
    func void DoForSphere(var func _) {
        var MEMINT_HelperClass symb;
        var int theHandlerInt;
        theHandlerInt = MEM_ReadInt(MEM_ReadIntArray(contentSymbolTableAddress, symb - 1) + zCParSymbol_content_offset);
        
        _BC_ForAll(theHandlerInt, 1);
    };
    
    //************************************************
    //   Building on that: The Broadcast
    //************************************************
    
    var int   _BC_funcID;
    var int   _BC_CasterPtr;
    var C_NPC _BC_Caster;
    var int   _BC_ExcludeCaster;
    var int   _BC_SendToDead;
    
    func void _BC_CallAssessFunc(var C_NPC slf) {
        //ignore dead, unless they are explicitly included
        if (!slf.attribute[ATR_HITPOINTS] && !_BC_SendToDead) {
            return;
        };
        
        //ignore caster if this is wanted
        if (_BC_ExcludeCaster) {
            if (_BC_CasterPtr == MEM_InstToPtr(slf)) {
                return;
            };
        };
        
        MEM_PushInstParam(slf);
        MEM_PushInstParam(_BC_Caster);
        MEM_CallByID(_BC_funcID);
    };
    
    func void _BC_Broadcast(var C_NPC caster, var int funcID, var int excludeCaster, var int includeDead, var int includeShrinked) {
        _BC_ExcludeCaster = excludeCaster;
        _BC_Caster        = Hlp_GetNpc(caster);
        _BC_CasterPtr     = MEM_InstToPtr(caster);
        _BC_SendToDead    = includeDead;
        _BC_funcID        = funcID;
        
        if (includeShrinked) {
            DoForAll(_BC_CallAssessFunc);
        } else {
            DoForSphere(_BC_CallAssessFunc);
        };
    };
    
    func void Broadcast  (var C_NPC caster, var func _) {
        var MEMINT_HelperClass symb;
        var int reactionFuncID;
        reactionFuncID = MEM_ReadInt(MEM_ReadIntArray(contentSymbolTableAddress, symb - 1) + zCParSymbol_content_offset);
        
        _BC_Broadcast(caster, reactionFuncID, 0, 0, 0);
    };
    
    func void BroadcastEx(var C_NPC caster, var func _, var int excludeCaster, var int includeDead, var int includeShrinked) {
        var MEMINT_HelperClass symb;
        var int reactionFuncID;
        reactionFuncID = MEM_ReadInt(MEM_ReadIntArray(contentSymbolTableAddress, symb - 4) + zCParSymbol_content_offset);
        
        _BC_Broadcast(caster, reactionFuncID, excludeCaster, includeDead, includeShrinked);
    };
    Ich hoffe das alles funktioniert und das Skript manchem nützt.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  8. View Forum Posts #8 Reply With Quote
    now also in your universe  Milky-Way's Avatar
    Join Date
    Jun 2007
    Posts
    13,335
     
    Milky-Way is offline
    Also funktioniert jetzt auch var func als Parameter? Schöner als Strings

    Was muss ich denn machen, um vom Alten aufs Neue umzusteigen? Wenn ich es richtig sehe, ist jetzt statt allen Broadcasts in einer Funktion mit ID zu unterscheiden eine eigene Funktion für jede "alte" ID zu machen? Und zusätzlich dann den Broadcast bearbeiten und statt einer ID die Funktion übergeben. Richtig?
    (und die alte Broadcast-Datei darf nicht mehr geparst werden)

  9. Visit Homepage View Forum Posts #9 Reply With Quote
    Exodus Sektenspinner's Avatar
    Join Date
    Jul 2004
    Location
    Karlsruhe
    Posts
    7,827
     
    Sektenspinner is offline
    Quote Originally Posted by Milky-Way View Post
    Also funktioniert jetzt auch var func als Parameter? Schöner als Strings

    Was muss ich denn machen, um vom Alten aufs Neue umzusteigen? Wenn ich es richtig sehe, ist jetzt statt allen Broadcasts in einer Funktion mit ID zu unterscheiden eine eigene Funktion für jede "alte" ID zu machen? Und zusätzlich dann den Broadcast bearbeiten und statt einer ID die Funktion übergeben. Richtig?
    (und die alte Broadcast-Datei darf nicht mehr geparst werden)
    Besser hätte ich es nicht beschreiben können.
    Desweiteren steht das "Ex" in BroadcastEx nicht mehr für "Exklusive dem Caster" sondern für "Extended" und es gibt drei Parameter zu übergeben. Bei manchen Broadcasts bei denen es eigentlich keinen logischen Caster gibt, will man vielleicht DoForSphere verwenden.
    Wenn man BC_ALLOW_DUPLICATES, B_BeforeFirstBroadCast oder B_AfterLastBroadCast genutzt hat, muss man das nun auch abändern, das gibt es so nicht mehr.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  10. View Forum Posts #10 Reply With Quote
    now also in your universe  Milky-Way's Avatar
    Join Date
    Jun 2007
    Posts
    13,335
     
    Milky-Way is offline
    Hat es auch noch weitere spürbare Vorteile außer in der Handhabung?

  11. Visit Homepage View Forum Posts #11 Reply With Quote
    Exodus Sektenspinner's Avatar
    Join Date
    Jul 2004
    Location
    Karlsruhe
    Posts
    7,827
     
    Sektenspinner is offline
    Quote Originally Posted by Milky
    Hat es auch noch weitere spürbare Vorteile außer in der Handhabung?
    Nicht wirklich.

    Was die Effizienz angeht: Das alte System erzeugt viele Npcs am WP tot, was Gothic aber nur geringfügig belasten sollte. Die Iteration selbst dürfte ähnlich effizient sein wie zuvor.
    Das alte System hat CallByString benutzt, was jedesmal eine zSpy-Info provoziert ("U:RTN:Routine change"), was aber auch nicht wirklich stört.

    Die Vorteile in der Handhabung sind wirklich das entscheidende. Das Skript kann man sich einfach irgendwo hinkopieren und es läuft (falls man Ikarus hat). Wenn jemand ein Skript schreibt, was auf den Broadcasts aufbaut, kann er es auch einfach posten und es ist als solches (aufbauend auf den Broadcasts) funktionsfähig, ohne, dass ein Nutzer selbst Änderungen an seiner B_AssessBroadcast vornehmen muss.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  12. View Forum Posts #12 Reply With Quote
    Legende der Amazonen Bisasam's Avatar
    Join Date
    Dec 2006
    Location
    Meine Faust in Sinis Gesicht
    Posts
    8,825
     
    Bisasam is offline
    Hat schonmal jemand versucht, diese Funktionen für Gothic 1 zu benutzen?
    Theoretisch müsste das ja funktionieren, wenn man eine entsprechende Ikarus-Version hat.

    Ich probiere das mal aus und schaue wie die Kompatibilität ausfällt.

    edit: Ja, die Broadcasts lassen sich ohne Änderungen in Gothic 1 einsetzen. Keine Abstürze oder Schwierigkeiten. Außer, dass mir aus irgendeinem Grund geprintet wird, dass sich Zombies in der Burg im Alten Lager befinden, obwohl ich nur die Namen aller Leute in 50m Entfernung haben wollte...


    "Das erinnert doch sehr erfreulich an das, was man sich als Gothicfan wünscht!"
    -Korallenkette
    Last edited by Bisasam; 14.07.2017 at 17:23.

  13. View Forum Posts #13 Reply With Quote
    Local Hero Mark56's Avatar
    Join Date
    Sep 2010
    Posts
    225
     
    Mark56 is offline
    Works without problem. Using smaller circle is good, broadcasting all npcs takes FPS away quickly

  14. View Forum Posts #14 Reply With Quote
    Ranger
    Join Date
    Feb 2017
    Posts
    136
     
    F a w k e s is offline

    G1 Resurrection Spell

    Hello folks,
    I have finished recently my Beliar's resurrection spell. Might be someone else can find it useful as well

    Spell in action:
    https://youtu.be/PhNu5aIm0z0

    What will you need to get it working:
    Ikarus 1.2
    Lego 2.5.0
    Broadcasts package

    I am using 'new' animation t_ZDeadB_2_Stand -> basically renamed T_DEADB animation for Zombies - however added to 'HUMANS.MDS'.
    In order to get t_ZDeadB_2_Stand animation working properly, you will need to have this file 'Zom_DeadB_M01.ASC' in folder: _work\Data\Anims\
    (You will probably have to use GothicSourcer to get Zom_DeadB_M01.ASC out of compiled ZOMBIE.MDH)

    Then edit file 'HUMANS.MDS' in the same folder and add to aniEnum these entries below
    Code:
        aniEnum
        {
            .
            .
            .
            standard animation entries
            .
            .
            .
            
            // MOD: Our 'new' animation
            
            //T_DEADB from HUMANS_ZOMBIE.MDS - just renamed, and with removed eventSFX ZOM_DIE
            ani            ("t_ZDeadB"                        1    "s_DeadB"        0.1    0.0    M.    "Zom_DeadB_M01.asc"        F    1    159    FPS:15)
            {
                //*eventSFX    (2    "ZOM_DIE"    EMPTY_SLOT    )
                *eventPFX        (1     1    "MFX_DESTROYUNDEAD_SOUL_BACK"    "BIP01 SPINE2"        ATTACH    )
                *eventPFX        (10     2    "MFX_DESTROYUNDEAD_SOUL_CLOUD"    "BIP01 L Hand"        ATTACH    )
                *eventPFX        (20     3    "MFX_DESTROYUNDEAD_SOUL_CLOUD"    "BIP01 R Hand"        ATTACH    )
                *eventPFX        (30     4    "MFX_DESTROYUNDEAD_SOUL_CLOUD"    "BIP01 L Foot"        ATTACH    )
                *eventSFX    (34    "M_FALL_SMALL"    EMPTY_SLOT    )
                *eventPFX        (40     5    "MFX_DESTROYUNDEAD_SOUL_CLOUD"    "BIP01 R Foot"        ATTACH    )
                *eventPFX        (50     6    "MFX_DESTROYUNDEAD_SOUL_CLOUD"    "BIP01 Head"        ATTACH    )
                *eventPFX        (60     7    "MFX_DESTROYUNDEAD_SOUL_CLOUD"    "BIP01 L UpperArm"    ATTACH    )
                *eventPFX        (70     8    "MFX_DESTROYUNDEAD_SOUL_CLOUD"    "BIP01 R UpperArm"    ATTACH    )
                *eventPFX        (80     9    "MFX_DESTROYUNDEAD_SOUL_CLOUD"    "BIP01"            ATTACH    )
    
                *eventPFX        (120     1    "MFX_DESTROYUNDEAD_SOUL_BACK"    "BIP01 SPINE2"        ATTACH    )
            }
    
            //Reversed animation t_ZDeadB
            aniAlias        ("t_ZDeadB_2_Stand"                    1    ""            0.0    0.0    M.    "t_ZDeadB"            R)
        }

    Here comes the code:
    Code:
    /***
    Function removes items from inv_category.
    Exception: equipped armor, items with ITEM_MISSION flag.
    ***/
    FUNC VOID NPC_Remove_Inventory_Category (var C_NPC slf, var int inv_category)
    {
        var int p;
        var int itm_count;
        var int itm_instance;
        
        var int itm_slot;
        
        itm_slot = 0;
        
        //Loop
        p = MEM_StackPos.position;
    
        //Is there any item in itm_slot ?
        if (Npc_GetInvItemBySlot (slf, inv_category, itm_slot) > 0)
        {
            itm_instance = Hlp_GetInstanceID (item);
    
            //We don't want to remove armor using this function
            if (inv_category == INV_ARMOR)
            {
                if (NPC_GetArmor (slf) == itm_instance)
                {
                    itm_slot = itm_slot + 1;
                    MEM_StackPos.position = p;
                };
            };
            
            //We don't want to remove ITEM_MISSION items using this function
            if (item.MainFlag & ITEM_MISSION)
            {
                itm_slot = itm_slot + 1;
                MEM_StackPos.position = p;
            };
    
            /***
            For whatever reason (Innos help me, I love Gothic, but sometimes I would just ... strangle it!) following items cannot be removed using NPC_RemoveInvItems, but they have to be removed by NPC_RemoveInvItem !?
            ***/
            if ((inv_category == INV_WEAPON) && (item.MainFlag != ITEM_KAT_MUN))
            || (inv_category == INV_DOC)
            || !(item.Flags & ITEM_MULTI)
            {
                NPC_RemoveInvItem (slf, itm_instance);    
            } else
            {
                itm_count = NPC_HasItems (slf, itm_instance);
                NPC_RemoveInvItems (slf, itm_instance, itm_count);
            };
            
            MEM_StackPos.position = p;
        };    
    };
    
    /***
    Function removes complete inventory of NPC
    Exception: equipped armor, items with ITEM_MISSION flag.
    ***/
    FUNC VOID NPC_Remove_Inventory (var C_NPC slf)
    {
        NPC_Remove_Inventory_Category (slf, INV_WEAPON);
        NPC_Remove_Inventory_Category (slf, INV_ARMOR);
        NPC_Remove_Inventory_Category (slf, INV_RUNE);
        NPC_Remove_Inventory_Category (slf, INV_MAGIC);
        NPC_Remove_Inventory_Category (slf, INV_FOOD);
        NPC_Remove_Inventory_Category (slf, INV_POTION);
        NPC_Remove_Inventory_Category (slf, INV_DOC);
        NPC_Remove_Inventory_Category (slf, INV_MISC);
    };
    
    /***
    Following function has to be called from AI Queue - using AI_Function further below.
    I am not sure why - but if I would apply OverlayMDS before playing animation t_ZDeadB_2_Stand - animation would not work.
    When OverlayMDS is applied after playing this animation - everything works fine.
    ***/
    
    FUNC VOID Zombie_Revenant_AIQ_01 ()
    {
        Mdl_ApplyOverlayMDS (self, "HUMANS_ZOMBIE.MDS");
    };
    
    FUNC VOID BC_Beliars_Resurrection (var C_NPC slf, var C_NPC npc)
    {
        //We are looking for dead humans, not that far from hero
        if (NPC_IsHuman (slf))
        && (NPC_IsDead (slf) == TRUE)
        && (NPC_GetDistToNPC (slf, npc) < 5000)
        {
            //We don't want to talk to zombie
            NPC_PercDisable (slf, PERC_ASSESSTALK); 
            
            //Let's get rid of the weapons
            NPC_Remove_Inventory_Category (slf, INV_WEAPON);
    
            //Clear AI Queue, just in case !
            NPC_ClearAIQueue (slf);
    
            //Red aura effect
            Wld_PlayEffect ("SPELLFX_MASSDEATH_TARGET", slf, slf, 0, 0, 0, FALSE);
    
            //--- Adjust stats
            if (slf.attribute [ATR_HITPOINTS_MAX] < 250)
            {
                slf.attribute [ATR_HITPOINTS_MAX]     = 250;
            };
            
            slf.attribute [ATR_STRENGTH]         = 140;
            slf.attribute [ATR_DEXTERITY]         = 140;
            
            slf.protection [PROT_BLUNT]         = 130;
            slf.protection [PROT_EDGE]         = 130;
            slf.protection [PROT_POINT]         = 9999;        //
            slf.protection [PROT_FIRE]         = 100;
            slf.protection [PROT_FLY]         = 500;        //zombie should be reasonably resistant to fall damage
            slf.protection [PROT_MAGIC]         = 100;
            //---
            
            //Revive NPC
            slf.attribute [ATR_HITPOINTS] = slf.attribute [ATR_HITPOINTS_MAX];
            
            //Play animation - reversal of the one used for dying zombie
            AI_PlayAni (slf, "T_ZDEADB_2_STAND");
            
            //Apply OverlayMDS HUMANS_ZOMBIE.MDS
            AI_Function (slf, Zombie_Revenant_AIQ_01);
            
            //Stand up - just in case
            AI_StandUp (slf);
    
            //--- ZS_MM_SummonedByPC - variables ---
            slf.aivar [AIV_HASDEFEATEDSC]         = 500;
    
            //Time after which NPC's health will decrease
            slf.aivar [AIV_ISLOOKING]         = 1;
            
            //We don't want our zombie to be attacking us
            slf.aivar [AIV_MOVINGMOB]         = TRUE;
            slf.aivar [AIV_PARTYMEMBER]         = TRUE;    
            //--- 
    
            //Chnage guild to GIL_ZOMBIE
            NPC_SetTrueGuild (slf, GIL_ZOMBIE);
            slf.Guild = GIL_ZOMBIE;
    
            //We HAVE to use this to 'override' daily NPC routines with ZS_MM_SummonedByPC - otherwise NPC once despawned (if you would run away) would just continue with it's own routine!!
            
            TA_BeginOverlay (slf);
            TA (slf, 0, 23, ZS_MM_SummonedByPC, slf.WP);
            TA_EndOverlay (slf);
    
            //Start ZS_MM_SummonedByPC
            AI_StartState (slf, ZS_MM_SummonedByPC, 1, "");
        };
    };

    And finally - to perform resurrection - call this function (when spell is casted for example):
    Code:
    BroadcastEx (self, BC_Beliars_Resurrection, 1, 1, 1);

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
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