Zachowanie animacji 4552 6

O temacie

Autor Siemekk

Zaczęty 12.12.2016 roku

Wyświetleń 4552

Odpowiedzi 6

Siemekk

Siemekk

Złote Wrota
posty2143
Propsy1154
ProfesjaProgramista
  • Złote Wrota

Siemekk
Złote Wrota

Zachowanie animacji
2016-12-12, 16:00(Ostatnia zmiana: 2016-12-13, 19:18)
Na początku podziękowania dla @bgb który kiedyś mi pięknie napisał co zrobić, aby animacja się zachowała... Ok. w takim razie Let's go.
Wymagany Ikarus oraz pakiet Broadcasts
Teraz omówmy o co chodzi. Jak wiemy, gdy damy npc OverlayMds dla nowego stylu walki, po wczytaniu walczy on po staremu... Opatentowałem jak prosto temu zaradzić... Wystarczy wykorzystać 1 Aivar, kilka warunków oraz pakiet Broadcasts.
Teraz do sedna ;)
Zacznijmy od stworzenia jednej stałej  w pliku AI_Constants.d
const int AIV_Broadcasts_Anim = 91;Pięknie. Teraz wybierzmy naszego npc. U mnie będzie to Hagen, ponieważ musi posiadać u mnie arcymistrza.
instance PAL_200_HAGEN(NPC_DEFAULT)
{
name[0] = "Lord Hagen";
guild = GIL_PAL;
id = 200;
voice = 4;
flags = NPC_FLAG_IMMORTAL;
npctype = NPCTYPE_MAIN;
aivar[AIV_TOUGHGUY] = TRUE;
aivar[AIV_TOUGHGUYNEWSOVERRIDE] = TRUE;
aivar[AIV_IGNORE_MURDER] = TRUE;
aivar[AIV_IGNORE_THEFT] = TRUE;
aivar[AIV_IGNORE_SHEEPKILLER] = TRUE;
/*
        itd.

*/
};
Dodajmy mu nasz aivar w następujący sposób:
aivar[AIV_Broadcasts_Anim] = 1; //Można zapisać na stałych co bardziej polecam, mimo to dla przykładu dajmy 1
Git. To teraz część Ikarusowa. Napiszmy funkcję BS_SaveAnim()
Gdzie w argumencie musi być c_npc.
Czyli tak:
func void BS_SaveAnim(var c_npc slf)
{
/*I tutaj dajemy warunki w zależności od ilości stylów. Ja dam tutaj jeden dla przykładu ;) */
if(slf.aivar[AIV_Broadcasts_Anim]==1)// arcymistrz
{
Mdl_RemoveOverlayMds(slf,"Humans_1hst2.mds"); //Wyłącz mu stary styl (ten bo ma >60% walki mieczem)
Mdl_RemoveOverlayMds(slf,"SHIELD_UNSKILLED.mds"); //Wyłącz mu obecny styl
Mdl_ApplyOverlayMds(slf,"SHIELD_UNSKILLED.mds");//I włącz go na nowo...
};
};
Gotowe! Od tej pory każdy npc którego aivar[AIV_Broadcasts_Anim] ma wartość jeden będzie walczył z ustalonym stylem walki!
Jednak to nie koniec. Musimy to wywołać... Ale jak? Nic prostszego! W Init_Global (startup.d) dodajemy taką linijkę:
DoForAll(BS_SaveAnim); //Słusznie zauważył [member=12353]Xardas47[/member] DoForAll będzie lepsze bo nie wywołujemy tego co klatkę ;)
Jeżeli jakieś problemy występują to śmiało piszcie ;)
 

P.S A Splash w szafie i nie ma psychy by mi dać bana.

Xardas47

Xardas47

Użytkownicy
Mhroczny charakterek
posty249
Propsy150
ProfesjaProgramista
  • Użytkownicy
  • Mhroczny charakterek
Spoko poradnik, tylko mogłeś napisać jak działa pakiet broadcast - wykonuję daną funkcje x razy (gdzie x to liczba wszystkich lub pobliskich npc, przyjmując jako argument kolejnych npc.

No i jeszcze tak się zastanawiam czy nie powinieneś wykorzystać DoForAll (Pewnie zadziała dużo wolniej), DoForSphere wykonuję funkcję tylko dla enpeców w odległości 40 metrów od kamery więc nie zawsze będzie działać.
 

Vic7im

Vic7im

Użytkownicy
posty84
Propsy92
Profesjabrak
  • Użytkownicy
Spoko poradnik, tylko mogłeś napisać jak działa pakiet broadcast - wykonuję daną funkcje x razy (gdzie x to liczba wszystkich lub pobliskich npc, przyjmując jako argument kolejnych npc.

No i jeszcze tak się zastanawiam czy nie powinieneś wykorzystać DoForAll (Pewnie zadziała dużo wolniej), DoForSphere wykonuję funkcję tylko dla enpeców w odległości 40 metrów od kamery więc nie zawsze będzie działać.

Depends, if the function "resets" NPC AI, stopping their routines for a split second, DoForAll would be better imo. You put it at every EnterXWorld and in the game_init and that's it.
If it doesn't break the routines a timed, looping function would work too, but the problem would be for NPCs having tens of thousands of .mds files overwriting one other (just assuming they'll do, not really sure about that)

Thanks for the script Siemekk!!!
 

Vic7im

Vic7im

Użytkownicy
posty84
Propsy92
Profesjabrak
  • Użytkownicy
Hey Siemekk, I get an access violation error using this script.

In AI_Constants I have
const int AIV_BROADCASTS_ANIM = 95;
Broadcast function copy-pasted from WoG, put right after LeGo
http://forum.worldofplayers.de/forum/threads/775333-Script-Broadcasts?p=17232705&viewfull=1#post17232705

Put    "aivar[AIV_Broadcasts_Anim] = 1;   " in Cedric,

Copy-pasted your function (in order, it's one of the last ones before Startup.d

Gothic-Sourcer doesn't create any errors of sorts, but once I start the game it simply crashes.

Crash report:
Spoiler
======================================= UNHANDLED EXCEPTION OCCURED ======================================================
======================================= CRASH INFOS: =====================================================================
Gothic II - 2.6 (fix), Parser Version: 50
User:  KEKBUR,  CPUType: 586,  Mem: 0 MB total, 0 MB free
Startup Options:
=============================================== CALLSTACK : ==============================================================
0023:0079249D (0x00003FDB 0x00AB4108 0x00000000 0x00AB40C0) Gothic2.exe, zCParser::DoStack()+2877 byte(s), P:\dev\g2addon\release\ZenGin\_ulf\zParser.cpp, line 1405+40 byte(s)
0023:00792504 (0x00003FDB 0x00AB4108 0x00000000 0x00AB40C0) Gothic2.exe, zCParser::DoStack()+2980 byte(s), P:\dev\g2addon\release\ZenGin\_ulf\zParser.cpp, line 1415
0023:00792504 (0x0002052C 0x183B6414 0x00AB4118 0x00AB40C0) Gothic2.exe, zCParser::DoStack()+2980 byte(s), P:\dev\g2addon\release\ZenGin\_ulf\zParser.cpp, line 1415
0023:00792504 (0x000206E9 0x0000A4CC 0x0082E6F0 0x15C895E0) Gothic2.exe, zCParser::DoStack()+2980 byte(s), P:\dev\g2addon\release\ZenGin\_ulf\zParser.cpp, line 1415
0023:00792CBF (0x00AB40C0 0x0000A4CC 0x0135FA9C 0x0135FAA0) Gothic2.exe, zCParser::CallFunc()+719 byte(s), P:\dev\g2addon\release\ZenGin\_ulf\zParser.cpp, line 1551
0023:006C20BF (0x0135FBD4 0x15C895E0 0x0135FBD0 0x0135FB00) Gothic2.exe, oCGame::CallScriptInit()+351 byte(s), P:\dev\g2addon\release\Gothic\_ulf\oGame.cpp, line 886
0023:006C9FE0 (0x0135FA9C 0x0135FB6C 0xFFFFFFFE 0x0135FB6C) Gothic2.exe, oCGame::LoadWorldStartup()+976 byte(s), P:\dev\g2addon\release\Gothic\_ulf\oGame.cpp, line 3150
0023:006C92DE (0xFFFFFFFE 0x0135FB00 0x18D5A26E 0x0135FCA0) Gothic2.exe, oCGame::LoadWorld()+558 byte(s), P:\dev\g2addon\release\Gothic\_ulf\oGame.cpp, line 2902
0023:006C6696 (0xFFFFFFFE 0x0135FBD0 0x0082E6F0 0x00000000) Gothic2.exe, oCGame::LoadGame()+246 byte(s), P:\dev\g2addon\release\Gothic\_ulf\oGame.cpp, line 2147
0023:00429BF9 (0x00000015 0x00400000 0x01723F4C 0x0135FEC4) Gothic2.exe, CGameManager::Menu()+2345 byte(s), P:\dev\g2addon\release\Gothic\_bert\oGameManager.cpp, line 1474
0023:00425C35 (0x0082F0EC 0x00000001 0x001105DE 0x15C895E0) Gothic2.exe, CGameManager::Run()+1029 byte(s), P:\dev\g2addon\release\Gothic\_bert\oGameManager.cpp, line 713
0023:0078188B (0x0000002C 0x00228ED9 0x00000016 0x00000000) Gothic2.exe, MainProg()+75 byte(s), P:\dev\g2addon\release\Gothic\_ulf\Phoenix.cpp, line 111
0023:00503270 (0x00400000 0x00000000 0x01723F4C 0x00000001) Gothic2.exe, HandledWinMain()+928 byte(s), P:\dev\g2addon\release\ZenGin\_carsten\zWin32.cpp, line 1169
0023:00502DFD (0x0135FEC8 0x00000000 0x01723F4C 0x00000001) Gothic2.exe, WinMain()+141 byte(s), P:\dev\g2addon\release\ZenGin\_carsten\zWin32.cpp, line 1054+17 byte(s)
0023:007D43F8 (0x00000004 0x0000FFFF 0x000000B8 0x00000000) Gothic2.exe, WinMainCRTStartup()+224 byte(s)
 

Siemekk

Siemekk

Złote Wrota
posty2143
Propsy1154
ProfesjaProgramista
  • Złote Wrota
Can you share function?
 

P.S A Splash w szafie i nie ma psychy by mi dać bana.

Vic7im

Vic7im

Użytkownicy
posty84
Propsy92
Profesjabrak
  • Użytkownicy
Can you share function?

It's exactly what you wrote :)

Broadcast Function
Spoiler
//#################################################
//
//    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);
};

In AI_constants I have
const int AIV_BROADCASTS_ANIM = 95;
I made a new file and pasted your function in it
func void BS_SaveAnim(var c_npc slf)
{
/*I tutaj dajemy warunki w zależności od ilości stylów. Ja dam tutaj jeden dla przykładu ;) */
if(slf.aivar[AIV_Broadcasts_Anim]==1)// arcymistrz
{
Mdl_RemoveOverlayMds(slf,"Humans_1hst2.mds"); //Wyłącz mu stary styl (ten bo ma >60% walki mieczem)
Mdl_RemoveOverlayMds(slf,"SHIELD_UNSKILLED.mds"); //Wyłącz mu obecny styl
Mdl_ApplyOverlayMds(slf,"SHIELD_UNSKILLED.mds");//I włącz go na nowo...
};
};


Then put this: aivar[AIV_Broadcasts_Anim] = 1;
On Cedric:

instance PAL_216_CEDRIC(NPC_DEFAULT)
{
name[0] = "Cedric";
guild = GIL_PAL;
id = 216;
voice = 12;
flags = 0;
npctype = NPCTYPE_MAIN;
b_setattributestochapter(self,6);
fight_tactic = FAI_HUMAN_MASTER;
aivar[AIV_NPCSHIELD] = TRUE;
EquipItem(self,itmw_1h_pal_sword);
EquipItem(self,itar_palshield2);
[color=red]        aivar[AIV_Broadcasts_Anim] = 1;[/color]
b_createambientinv(self);
b_setnpcvisual(self,MALE,"Hum_Head_Fighter",FACE_N_NORMALBART10,BODYTEX_N,itar_pal_h);
Mdl_SetModelFatness(self,0);
Mdl_ApplyOverlayMds(self,"Humans_Militia.mds");
Mdl_ApplyOverlayMds(self,"HUMANS_TALKGESTURES2.mds");
b_givenpctalents(self);
b_setfightskills(self,85);
daily_routine = rtn_start_216;
};


func void rtn_start_216()
{
ta_practice_sword(7,0,19,0,"NW_CITY_LHCASTLE_BASE_04");
ta_sleep(19,0,7,0,"NW_CITY_LEOMAR_BED_03");
};

Wrote this in the Startup.d
func void init_global()
{
//Ikarus and LeGo startup
//things
DoForAll(BS_SaveAnim);
//other things
}

Load the game up and it crashes =(
I've changed the animation SHIELD_UNSKILLED with SHIELD_ST3
 

Siemekk

Siemekk

Złote Wrota
posty2143
Propsy1154
ProfesjaProgramista
  • Złote Wrota
Add to Cedric code:
Mdl_ApplyOverlayMds(self,"Shield_Unskilled.mds");
And try change DoForAll to DoForSphere.
 

P.S A Splash w szafie i nie ma psychy by mi dać bana.


0 użytkowników i 1 Gość przegląda ten wątek.
0 użytkowników
Do góry