Pokaż wiadomości

Ta sekcja pozwala Ci zobaczyć wszystkie wiadomości wysłane przez tego użytkownika. Zwróć uwagę, że możesz widzieć tylko wiadomości wysłane w działach do których masz aktualnie dostęp.


Wiadomości - Kirgo2

Strony: [1] 2 3
1
Skrypty / Długa bądź wieczna noc w G1
« dnia: Dzisiaj o 15:00 »
func void EndlessNight ()
{
var int ptr; ptr = MEM_InstToPtr (MEM_SkyController);
var int skystateslist; skystateslist = MEM_ReadInt (ptr+316);
ptr = MEM_ReadIntArray (skystateslist, 4);

var int R_poly; R_poly = MEM_ReadInt (ptr+4);
var int G_poly; G_poly = MEM_ReadInt (ptr+8);
var int B_poly; B_poly = MEM_ReadInt (ptr+12);

var int R_fog; R_fog = MEM_ReadInt (ptr+16);
var int G_fog; G_fog = MEM_ReadInt (ptr+20);
var int B_fog; B_fog = MEM_ReadInt (ptr+24);

var int i; i = 0;

repeat (i, 7);
ptr = MEM_ReadIntArray (skystateslist, i);
MEM_WriteInt (ptr+4, R_poly);
MEM_WriteInt (ptr+8, G_poly);
MEM_WriteInt (ptr+12, B_poly);
MEM_WriteInt (ptr+16, R_fog);
MEM_WriteInt (ptr+20, G_fog);
MEM_WriteInt (ptr+24, B_fog);
end;
};

Przetestowałem w Gothic 1. Funkcja działa bardzo fajnie. Jest tylko problem z godzinami od szóstej (rano) do dziesiątej (rano). O szóstej (rano) jest bardzo widno, podobnie o siódmej (rano). Dopiero o dziewiątej (rano) zaczyna się robić trochę bardziej wieczorowo ale o nocy też trudno tu mówić. Szczególnie ta ósma (rano) i dziewiąta (rano) odstają. Oprócz tego wszystko ładnie śmiga :)

2
@frN i @Gother Dobra, rozgryzłem. frN mnie naprowadził, że parsowałem wyłącznie plik Gothic.src.

Rozwiązanie było głupio proste. Zamiast parsować przez Spacera po prostu trzeba było puścić GothicStarter_mod.exe znajdujący się w folderze Gothic\system. Jako początkujący modder z ostrożności wolałem parsować przez Spacera bo wiedziałem, że przed parsowaniem trzeba usunąć pliki OU.csl i OU.bin a w przypadku parsowania przez GothicStarter_mod.exe nie wiedziałem czy nie trzeba czego analogicznie usuwać by się nie duplikowało.

Temat do zamknięcia. Oczywiście dziękuję obu Panom i leci po propsie.

3
@frN W Spacerze biorę "Reparse Scriptfiles" i zaznaczam "Gothic.src".

4
Co do umieszczenia we właściwym folderze i tekstur w formacie TEX to powinno się zgadzać
Spoiler
MFX_MagicCloud.tga i LIGHTNING_BIG_A0.TGA są w Gothic\_work\DATA\TEXTURES\Effects\Magic

MFX_MAGICCLOUD-C.TEX i LIGHTNING_BIG_A0-C.TEX są w Gothic\_work\DATA\TEXTURES\_COMPILED

LIGHTNING_BIG_A0.TGA i LIGHTNING_BIG_A0-C.TEX to są rzeczy oryginalnie występujące w Gothic 1 i ich nie ruszałem.

Tekstury więc występują także w wersji skompilowanej i z tego co widzę to we właściwych lokacjach.

DX11, texturepacków czy innych dodatków, które mogłyby wpływać na tekstury czy efekt, który próbuję dodać nie używam. Dla jasności, plik Textures.vdf w folderze Gothic\Data mam zmieniony na Textures.vdf.disabled, więc to nie to.

Tak jak mi poradziłeś spróbowałem dokleić Wld_PlayEffect("spellFX_INCOVATION_RED",  self, self, 0, 0, 0, FALSE ); do sprawdzonych dialogów ale też się nie udało. Dla porównania dokleiłem do nich potem efekt z trzęsieniem ziemi Wld_PlayEffect("FX_EarthQuake",  self, self, 0, 0, 0, FALSE ); i efekt z trzęsieniem ziemi działał zaś ten z czerwoną falą nie działał.

Wydaje mi się, że problemem jest to, że pliki VISUALFX.DAT i PARTICLEFX.DAT w moim modzie czegoś tak jakby nie zasysały. Już tłumaczę co mam na myśli.

Porównałem pliki VISUALFX.DAT z Gothica II i mojego moda do Gothica 1. W tym z Gothica II jest taki wycinek odnoszący się do "INVOCATION" (Piranie w plikach przekręcają ten wyraz też na "INCOVATION")

    0AT                    INVOCATION_RED
˙˙˙˙   ˙10252
    0A                   EFIXED
˙˙˙˙   ˙10253
    0A   č  }            BIP01
˙˙˙˙   ˙10254
    0A           (w        REDAMBIENCE
˙˙˙˙   ˙10255
    0At                    SFX_Circle
˙˙˙˙   ˙10256
    0A                   mINVOCATION_GREEN
˙˙˙˙   ˙10257
    0A   č               FIXED
˙˙˙˙   ˙10258
    0A           xf        BIP01
˙˙˙˙   ˙10259
    0AA                    POISON
˙˙˙˙   ˙10260
    0A                    SFX_Circle
˙˙˙˙   ˙10261
    0A   č  PR            INVOCATION_BLUE
˙˙˙˙   ˙10262
    0A                    FIXED
˙˙˙˙   ˙10263
    0Ao                    BIP01
˙˙˙˙   ˙10264
    0A                   "REDAMBIENCE
˙˙˙˙   ˙10265
    0A   č  0             SFX_Circle
˙˙˙˙   ˙10266
    0A                    INVOCATION_VIOLET
˙˙˙˙   ˙10267
    0AR                    FIXED
˙˙˙˙   ˙10268
    0A                   {BIP01
˙˙˙˙   ˙10269
    0A   č  8             CATACLYSM
˙˙˙˙   ˙10270
    0A           `0        SFX_Circle
˙˙˙˙   ˙10271
    0Ae                    INVOCATION_WHITE
˙˙˙˙   ˙10272
    0A                   NFIXED

oraz

     pA  Ř”     [  q   Ž  R      SPELLFX_INCOVATION_RED
     pA    ž     \  ö   Ş  R      SPELLFX_INCOVATION_GREEN
     pA  řD¨     ]  ő   ň  R      SPELLFX_INCOVATION_BLUE
     pA    ˛      ^ ř   :  R      SPELLFX_INCOVATION_VIOLET
     pA  ŘĽ     _  ú   ‚  R      SPELLFX_INCOVATION_WHITE

Tego czegoś nie ma w VISUALFX.DAT mojej modyfikacji, więc tak jakby ten VISUALFX.DAT z mojej modyfikacji czegoś nie "zassał". To jest fragment zassany z Visualfxinst.d


To samo z w przypadku PARTICLEFX.DAT. Plik PARTICLEFX.DAT z Gothica II zawiera fragment, którego brak w pliku PARTICLEFX.DAT z mojego moda.

     pA    ű     ‹ö  w   R *     INVOCATION
     `@       %   ÷  !  -R       INVOCATION_RED
     pA    '      'ű  s   ¤S 1     INVOCATION_WHITE
     pA    -      śű  }   ŔS 1     INVOCATION_BLUE
     pA    3      ü  t   ÜS 1     INVOCATION_GREEN
     pA    9      ‘ü  y   řS 1     INVOCATION_VIOLET

Więc jak mówiłem tak jakby pliki VISUALFX.DAT i PARTICLEFX.DAT w moim modzie czegoś nie zasysały.


5
@Gother Nie do końca zrozumiałem.

Próbuję dodać tę czerwoną falę z rutyny a nie efekty zniekształcenia ekranu występujące podczas rozmowy z poszukiwaczem.

6
Gothic 2 posiadał w mojej ocenie ciekawszą animację dobijania postaci, więc próbowałem ją przenieść. Efekt ten udało mi się osiągnąć metodą prób i błędów. Poniżej zamieszczam małą instrukcję. Jest to prosty poradnik napisany z myślą o takich parweniuszach jak ja lub o niedzielnych graczach, którzy chcieliby po prostu sobie dodać tą rzecz do gry.


Być może nie wszystkie pliki są niezbędne ale tutaj już się nie wypowiem bo nie wiem.

Do dzieła!


1. Po pierwsze musisz mieć wypakowane animacje.
Spoiler
Jeżeli ich nie masz to możesz to zrobić przykładowo za pomocą programu Gothic VDFS tool. Link do niego masz choćby tutaj https://themodders.org/index.php?topic=31909.0

Trzeba rozpakować plik anims.VDF znajdujący się w folderze Gothic\Data.

Wypakuj te rzeczy i wklej do folderu głównego folderu Gothica. W twoim folderze Gothic\_work\DATA\ANIMS powinny się wówczas pojawić pliki z animacjami.

Po wypakowaniu pliku tych plików zmień nazwę pliku anims.VDF znajdującego się w folderze Gothic\Data na anims.VDF.disabled



2. Otwórz plik Humans.MDS znajdujący się w Gothic\_work\DATA\ANIMS


3. Interesuje nas ten fragment pliku Humans.MDS

// Todesstoß - Entfernung zwischen Bip01 Angreifer und Bip01 Opfer ca. 200 cm
ani ("t_1hSFinish" 1 "" 0.1 0.1 M. "Hum_1hSFinish_M03.asc" F 1 139 FPS:10)
{
*eventSFX (35 "FIG_SwordFinal" EMPTY_SLOT )

}

aniAlias ("t_2hSFinish" 1 "" 0.1 0.1 M. "t_1hSFinish" F)


// Dead Anis für t_1hSFinish
ani ("t_Wounded_2_Dead" 1 "s_Dead" 0.1 0.1 M. "Hum_Wound2Dead_M01.asc" F 1 139 FPS:10 CVS:0.1)
{
// *eventSFX (36 "FIG_DummyDie" EMPTY_SLOT )
}
ani ("t_WoundedB_2_DeadB" 1 "s_DeadB" 0.1 0.1 M. "Hum_WoundB2DeadB_M01.asc" F 1 139 FPS:10 CVS:0.1)
{
// *eventSFX (36 "FIG_DummyDie" EMPTY_SLOT )



4. Podmieniasz wskazany w punkcie 3 fragment na to:

// Todesstoß - Entfernung zwischen Bip01 Angreifer und Bip01 Opfer ca. 200 cm
ani ("t_1hSFinish" 1 "" 0.1 0.1 M. "Hum_1hSFinish_M03.asc" F 1 139 FPS:10)
{
*eventSFX (35 "FIG_SwordFinal" EMPTY_SLOT )

}

aniAlias ("t_2hSFinish" 1 "" 0.1 0.1 M. "t_1hSFinish" F)


// Dead Anis für t_1hSFinish

ani ("t_Wounded_2_Dead" 1 "s_Dead" 0.1 0.1 M. "Hum_Wound2Dead_A01.asc" F 1 89 CVS:0.1)

ani ("t_WoundedB_2_DeadB" 1 "s_DeadB" 0.1 0.1 M. "Hum_WoundB2DeadB_A01.asc" F 1 89 CVS:0.1)



5. Teraz musisz skopiować animacje z Gothica 2 . Chodzi o kilka plików znajdujących się w folderze Gothic II\_work\data\Anims\_compiled Są to następujące pliki:

HUMANS-S_WOUNDED.MAN
HUMANS-S_WOUNDEDB.MAN
HUMANS-T_STAND_2_WOUNDED.MAN
HUMANS-T_STAND_2_WOUNDEDB.MAN
HUMANS-T_WOUNDED_2_DEAD.MAN
HUMANS-T_WOUNDED_2_STAND.MAN
HUMANS-T_WOUNDEDB_2_DEADB.MAN
HUMANS-T_WOUNDEDB_2_STAND.MAN

Możesz po prostu je wyszukać w tym folderze po frazie "wounded". Kopiujesz te pliki i wklejasz je do Gothic\_work\DATA\ANIMS\_COMPILED podmieniając istniejące w tym folderze oryginalne pliki z jedynki.


5. Gotowe! W Gothicu I pojawiły się animacje dobijania z Gothica II.


UWAGA: Przed tą całą podmianką najlepiej zrób sobie kopię zapasową plików z Gothica I, które będziesz podmieniał. Możesz po prostu je wyszukać w tym folderze po frazie "wounded" i skopiować w bezpieczne miejsce.

7
Hejka. Próbuję przenieść pewien efekt wizualny z Gothic 2 do Gothic 1. Efekt ten ma być związany z rutyną danej postaci - przenoszę z Gothica 2 rutynę "zs_circle", czyli tę rutynę ktorą wykonują poszukiwacze nad okiem Innosa w kamiennym kręgu. Rutyna działa tylko mam problem, że nie działa ten efekt wizualny z czarem.

Poniżej opiszę co dokładnie zrobiłem.


1. Wkleiłem do Visualfxinst.d w Gothic\_work\DATA\scripts\system\VISUALFX to:


///    XXXXXXXXXXXXXXXXXXXXXXXXXXX
///    XX  I N V O C A T I O N  XX
///    XXXXXXXXXXXXXXXXXXXXXXXXXXX

INSTANCE spellFX_INCOVATION_RED (CFx_Base_Proto)
{
visname_S = "INVOCATION_RED";
emtrjmode_s = "FIXED";
emTrjOriginNode = "BIP01";
lightpresetname = "REDAMBIENCE";
    sfxid = "SFX_Circle";
      sfxisambient = 1;
};

INSTANCE spellFX_INCOVATION_GREEN (CFx_Base_Proto)
{
visname_S = "INVOCATION_GREEN";
emtrjmode_s = "FIXED";
emTrjOriginNode = "BIP01";
lightpresetname = "POISON";
    sfxid = "SFX_Circle";
      sfxisambient = 1;
};

INSTANCE spellFX_INCOVATION_BLUE (CFx_Base_Proto)
{
visname_S = "INVOCATION_BLUE";
emtrjmode_s = "FIXED";
emTrjOriginNode = "BIP01";
lightpresetname = "REDAMBIENCE";
    sfxid = "SFX_Circle";
      sfxisambient = 1;
};

INSTANCE spellFX_INCOVATION_VIOLET (CFx_Base_Proto)
{
visname_S = "INVOCATION_VIOLET";
emtrjmode_s = "FIXED";
emTrjOriginNode = "BIP01";
lightpresetname = "CATACLYSM";
    sfxid = "SFX_Circle";
      sfxisambient = 1;
};

INSTANCE spellFX_INCOVATION_WHITE (CFx_Base_Proto)
{
visname_S = "INVOCATION_WHITE";
emtrjmode_s = "FIXED";
emTrjOriginNode = "BIP01";
lightpresetname = "WHITEBLEND";
    sfxid = "SFX_Circle";
      sfxisambient = 1;
};


2. Wkleiłem w PFXMagic.d w Gothic\_work\DATA\scripts\system\PFX to:


PROTOTYPE INVOCATION (C_PARTICLEFX)
{
     ppsvalue = 30;
     ppsscalekeys_s = "1 1 2 2 2 3 3 4 4 5";
     ppsissmooth = 1;
     ppsfps = 3;
     shptype_s = "CIRCLE";
     shpfor_s = "WORLD";
     shpoffsetvec_s = "0 0 0";
     shpdistribtype_s = "RAND";
     shpdim_s = "120";
     shpscalekeys_s = "1 2 3 4 5 6 7 8 9 10";
     shpscaleissmooth = 1;
     shpscalefps = 3;
     dirmode_s = "RAND";
     dirfor_s = "object";
     diranglehead = 90;
     dirangleheadvar = 45;
     dirangleelev = 90;
     dirangleelevvar = 45;
     velavg = 0.100000001;
     lsppartavg = 1500;
     lsppartvar = 300;
     flygravity_s = "0 0.00008 0";
     visname_s = "MFX_MAGICCLOUD.TGA";
     visorientation_s = "VELO";
     vistexisquadpoly = 1;
     vistexanifps = 25;
     vistexaniislooping = 2;
     vistexcolorstart_s = "255 0 0";
     vistexcolorend_s = "255 0 0";
     vissizestart_s = "20 20";
     vissizeendscale = 20;
     visalphafunc_s = "ADD";
     visalphastart = 255;
     trltexture_s = "LIGHTNING_BIG_A0.TGA";
};

INSTANCE INVOCATION_RED  (INVOCATION)
{
vistexcolorstart_s = "255 0 0";
    vistexcolorend_s = "255 0 0";
};

INSTANCE INVOCATION_WHITE  (INVOCATION)
{
vistexcolorstart_s = "255 255 255";
    vistexcolorend_s = "255 255 255";
};

INSTANCE INVOCATION_BLUE  (INVOCATION)
{
vistexcolorstart_s = "0 0 255";
    vistexcolorend_s = "0 0 255";
};

INSTANCE INVOCATION_GREEN  (INVOCATION)
{
vistexcolorstart_s = "0 200 200";
    vistexcolorend_s = "0 200 200";
};

INSTANCE INVOCATION_VIOLET  (INVOCATION)
{
vistexcolorstart_s = "200 0 255";
    vistexcolorend_s = "255 0 200";
};

3. Pliki z teksturami MFX_MAGICCLOUD.TGA, LIGHTNING_BIG_A0.TGA, MFX_MAGICCLOUD-C.TEX i LIGHTNING_BIG_A0-C.TEX znajdują się na właściwym miejscu

4. Wstawiłem też rutynę. Rutyna ładnie działa z małym acz znaczącym zastrzeżeniem...

// ************************************
// ZS_Circle für Auge Innos Beschwörung
// ************************************


func void ZS_Circle ()
{
B_SetPerception(self);

// ------ PercTime überschreiben ------
Npc_SetPercTime (self, 0.3);


AI_StandUp (self);
AI_SetWalkmode (self,NPC_WALK); // Walkmode für den Zustand
AI_GotoWP (self, self.wp); // Gehe zum Tagesablaufstart
AI_AlignToWP (self);
};

func int ZS_Circle_Loop ()
{
var int randy;

if (self.guild == GIL_DEMON)
{
randy = Hlp_Random (1000);

if (Npc_GetStateTime(self) > randy)
{
Wld_PlayEffect("FX_EarthQuake",  self, self, 0, 0, 0, FALSE );
Npc_SetStateTime (self, 0);
Wld_PlayEffect("spellFX_INCOVATION_RED",  self, self, 0, 0, 0, FALSE );
AI_PlayAni (self,"T_PRACTICEMAGIC5");
};
};

return LOOP_CONTINUE;
};

func void ZS_Circle_End ()
{

};

5. I teraz przechodzimy do sedna: NPC, któremu przypisano rutynę wykonuje magiczny gest ciałem, efekt trzęsienia ziemi występuje też ładnie ale... no właśnie. Nie ma tego czerwonego efektu od czaru. i w tym właśnie tkwi problem.

Oczywiście zreparsowałem plik Gothic.src.

Bardzo prosiłbym o jakieś wskazówki jak rozwiązać ten problem.

8
@BeziJuve póki co spróbuję się oswoić z programem a za jakiś czas przyjdzie pora na wskoczenie na wyższy poziom :)

9
@BeziJuve, dzięki sprawdzę. Są jakieś szczególne funkcje tego VSC na które warto zwrócić uwagę?

10
Czołem! Podrzucam skrypt do Gothic 1, który umożliwia przydzielanie ambientowych statystyk postaciom. Skrypt jest oczywiście w przeważającej mierze zrzynką analogicznego skryptu występującego w Gothic 2.

Przydaje się jeżeli chcesz z jednego miejsca zmieniać statystyki wielu postaciom zamiast każdorazowego wchodzenia do załóżmy 30 plików w folderze Gothic\_work\DATA\scripts\Content\Story\NPC W mojej ocenie całkiem użyteczna zabawka przy balansowaniu poziomu trudności w modyfikacji.

Oczywiście żeby ten skrypt działał w odniesieniu do danego NPC najpierw musisz w pliku tego NPC w folderze Gothic\_work\DATA\scripts\Content\Story\NPC wstawić odpowiednią funkcję ale nie uprzedzajmy faktów.

Wstawianie skryptu

1. Po pierwsze musisz wkleić poniższy skrypt. Gdzie? Ja wkleiłem w pliku B_Functions.d znajdującym się w folderze Gothic\DATA\scripts\Content\AI\AI_Intern
func void b_setambientnpcstats(var C_Npc slf,var int ambnpcstats)
{
Npc_SetTalentSkill(self,NPC_TALENT_MAGE,6);
if(ambnpcstats == 1) ///////zestaw statystyk nr 1
{
slf.level = 5;
slf.attribute[ATR_STRENGTH] = 30;
slf.attribute[ATR_DEXTERITY] = 10;
slf.attribute[ATR_MANA_MAX] = 0;
slf.attribute[ATR_MANA] = 0;
slf.attribute[ATR_HITPOINTS_MAX] = 200;
slf.attribute[ATR_HITPOINTS] = 200;
Npc_SetTalentSkill(self,NPC_TALENT_1H,1);
};
if(ambnpcstats == 2) ///////zestaw statystyk nr 2
{
slf.level = 5;
slf.attribute[ATR_STRENGTH] = 30;
slf.attribute[ATR_DEXTERITY] = 10;
slf.attribute[ATR_MANA_MAX] = 0;
slf.attribute[ATR_MANA] = 0;
slf.attribute[ATR_HITPOINTS_MAX] = 200;
slf.attribute[ATR_HITPOINTS] = 200;
Npc_SetTalentSkill(self,NPC_TALENT_1H,1);
};
if(ambnpcstats == 3) ///////zestaw statystyk nr 3
{
slf.level = 8;
slf.attribute[ATR_STRENGTH] = 60;
slf.attribute[ATR_DEXTERITY] = 25;
slf.attribute[ATR_MANA_MAX] = 50;
slf.attribute[ATR_MANA] = 50;
slf.attribute[ATR_HITPOINTS_MAX] = 340;
slf.attribute[ATR_HITPOINTS] = 340;
Npc_SetTalentSkill(self,NPC_TALENT_1H,1);
Npc_SetTalentSkill(self,NPC_TALENT_2H,1);
};
if(ambnpcstats == 4) ///////zestaw statystyk nr 4
{
slf.level = 8;
slf.attribute[ATR_STRENGTH] = 60;
slf.attribute[ATR_DEXTERITY] = 34;
slf.attribute[ATR_MANA_MAX] = 20;
slf.attribute[ATR_MANA] = 20;
slf.attribute[ATR_HITPOINTS_MAX] = 380;
slf.attribute[ATR_HITPOINTS] = 380;
Npc_SetTalentSkill(self,NPC_TALENT_1H,1);
Npc_SetTalentSkill(self,NPC_TALENT_2H,1);
};
if(ambnpcstats == 5) ///////zestaw statystyk nr 5 (możesz sobie dorobić 6,7,8 i ile chcesz takich zestawów)
{
slf.level = 8;
slf.attribute[ATR_STRENGTH] = 50;
slf.attribute[ATR_DEXTERITY] = 34;
slf.attribute[ATR_MANA_MAX] = 15;
slf.attribute[ATR_MANA] = 15;
slf.attribute[ATR_HITPOINTS_MAX] = 350;
slf.attribute[ATR_HITPOINTS] = 350;
Npc_SetTalentSkill(self,NPC_TALENT_1H,1);
Npc_SetTalentSkill(self,NPC_TALENT_2H,1);
};
slf.exp = 500 * ((slf.level + 1) / 2) * (slf.level + 1);
slf.exp_next = 500 * ((slf.level + 2) / 2) * (slf.level + 1);
};

Taka mała uwaga: czemu zalecam by wkleić to akurat do w pliku B_Functions.d? Otóż gra odczytuje rzeczy w pewnej kolejności. Jak poprzednio wstawiałem to do mojego ulubionego pliku B_InExtremo.d w Gothic\_work\DATA\scripts\Content\Story\B to gra nie zasysała tego skryptu a po wklejeniu w pliku B_Functions wszystko ładnie śmiga.

2. Po drugie musisz edytować pliki postaci, które chcesz objąć systemem ambientowych zestawów. Przykładowo wynajdujesz sobie plik VLK_560_Buddler I usuwasz w nim wszystko to co określone jest w zestawie czyli w naszym przypadku wywalasz fragmenty skryptu dotyczące:
- poziomu
- siły, zręczności, many
- punktów życia i max punktów życia
- umiejętności walki bronią

W miejsce statystyk w tym pliku NPC-a wstawiasz „B_SetAmbientNPCStats(self, 1);   /////// zestaw statystyk nr 1”. Jeżeli to ma być zestaw drugi to zamiast jedynki wstawiasz tam 2 („B_SetAmbientNPCStats(self, 2)”), itd.

Przykładowy plik po opisywanej obróbce będzie wyglądał tak:
 instance VLK_560_Buddler (Npc_Default)
{
//-------- primary data --------

name = Name_Buddler;
npctype = npctype_ambient;
guild = GIL_VLK;     


voice = 2;
id = 560;


//-------- abilities --------
B_SetAmbientNPCStats(self, 1); /////// zestaw statystyk nr 1


//-------- visuals --------
// animations
Mdl_SetVisual (self,"HUMANS.MDS");
Mdl_ApplyOverlayMds (self,"Humans_Tired.mds");
// body mesh, head mesh, hairmesh, face-tex, hair-tex, skin
Mdl_SetVisualBody (self,"hum_body_Naked0",3,1,"Hum_Head_Psionic", 67,  2, -1);

B_Scale (self);
Mdl_SetModelFatness (self, 0);

fight_tactic = FAI_HUMAN_COWARD;

//-------- Talents --------                                   


//-------- inventory --------                                   

EquipItem (self, ItMw_1h_Club_01);
CreateInvItem (self, ItFoApple);


//-------------Daily Routine-------------
daily_routine = Rtn_start_560;
};

FUNC VOID Rtn_start_560 ()
{
TA_Sleep (23,00,06,30,"OCR_HUT_16");
TA_StandAround (06,30,11,00,"OCR_OUTSIDE_HUT_16");
TA_WashSelf (11,00,11,20,"OCR_TO_HUT_17");
TA_SitCampfire (11,20,23,00,"OCR_OUTSIDE_HUT_16");
};


4. I gotowe. Teraz zamiast wchodzić do każdego pliku z osobna i edytować statystyki każdej postaci możesz masowo zmieniać statystyki z poziomu jednego pliku tekstowego. Oczywiście to ułatwienie dotyczy tylko tych NPC-ów, których uprzednio przydzieliłeś do jednego z zestawów. 

11
Prosta implementacja funkcji z Gothica II, która pomaga zwiększyć przejrzystość przy przeglądaniu asortymentu handlarzy. Funkcja sprawia, że po zakończeniu rozmowy z handlarzem z ekwipunku handlarza usuwane są śmieciowe rzeczy, które mu uprzednio sprzedaliśmy. Jak kogoś to bardzo interesuje to mój wkład twórczy ograniczył się do podmiany przedmiotów na te z Gothica I.

Wklejam gotowca dla oszczędności sił i czasu, bo nie ma sensu by każdy kolejny modder do swojego projektu wykonywał ten skrypt od nowa.

func void b_clearjunktradeinv(var C_NPC self)
{
////////orcish weapon
Npc_RemoveInvItems(self,itmw2horcaxe01,Npc_HasItems(self,itmw2horcaxe01));
Npc_RemoveInvItems(self,itmw2horcaxe02,Npc_HasItems(self,itmw2horcaxe02));
Npc_RemoveInvItems(self,itmw2horcaxe03,Npc_HasItems(self,itmw2horcaxe03));
Npc_RemoveInvItems(self,itmw2horcaxe04,Npc_HasItems(self,itmw2horcaxe04));

Npc_RemoveInvItems(self,itmw2horcmace01,Npc_HasItems(self,itmw2horcmace01));
Npc_RemoveInvItems(self,itmw2horcsword01,Npc_HasItems(self,itmw2horcsword01));
Npc_RemoveInvItems(self,itrworcstaff,Npc_HasItems(self,itrworcstaff));
Npc_RemoveInvItems(self,itmw2horcaxe01,Npc_HasItems(self,itmw2horcaxe01));
Npc_RemoveInvItems(self,itmw2horcaxe01,Npc_HasItems(self,itmw2horcaxe01));

////////Animaltrophy (without golems' hearts)
Npc_RemoveInvItems(self,itat_bloodfly_01,Npc_HasItems(self,itat_bloodfly_01));
Npc_RemoveInvItems(self,itat_bloodfly_02,Npc_HasItems(self,itat_bloodfly_02));
Npc_RemoveInvItems(self,itat_claws_01,Npc_HasItems(self,itat_claws_01));
Npc_RemoveInvItems(self,itat_crawler_01,Npc_HasItems(self,itat_crawler_01));
Npc_RemoveInvItems(self,itat_crawler_02,Npc_HasItems(self,itat_crawler_02));
Npc_RemoveInvItems(self,itat_lurker_01,Npc_HasItems(self,itat_lurker_01));
Npc_RemoveInvItems(self,itat_lurker_02,Npc_HasItems(self,itat_lurker_02));
Npc_RemoveInvItems(self,itat_shadow_01,Npc_HasItems(self,itat_shadow_01));
Npc_RemoveInvItems(self,itat_shadow_02,Npc_HasItems(self,itat_shadow_02));
Npc_RemoveInvItems(self,itat_swampshark_01,Npc_HasItems(self,itat_swampshark_01));
Npc_RemoveInvItems(self,itat_swampshark_02,Npc_HasItems(self,itat_swampshark_02));
Npc_RemoveInvItems(self,itat_teeth_01,Npc_HasItems(self,itat_teeth_01));
Npc_RemoveInvItems(self,itat_troll_01,Npc_HasItems(self,itat_troll_01));
Npc_RemoveInvItems(self,itat_troll_02,Npc_HasItems(self,itat_troll_02));
Npc_RemoveInvItems(self,itat_waran_01,Npc_HasItems(self,itat_waran_01));
Npc_RemoveInvItems(self,itat_wolf_01,Npc_HasItems(self,itat_wolf_01));
Npc_RemoveInvItems(self,itat_wolf_02,Npc_HasItems(self,itat_wolf_02));

////////Items
Npc_RemoveInvItems(self,itlstorchfirespit,Npc_HasItems(self,itlstorchfirespit));
Npc_RemoveInvItems(self,itmi_stuff_amphore_01,Npc_HasItems(self,itmi_stuff_amphore_01));
Npc_RemoveInvItems(self,itmi_stuff_barbknife_01,Npc_HasItems(self,itmi_stuff_barbknife_01));
Npc_RemoveInvItems(self,itmi_stuff_candel_01,Npc_HasItems(self,itmi_stuff_candel_01));
Npc_RemoveInvItems(self,itmi_stuff_cup_01,Npc_HasItems(self,itmi_stuff_cup_01));
Npc_RemoveInvItems(self,itmi_stuff_cup_02,Npc_HasItems(self,itmi_stuff_cup_02));
Npc_RemoveInvItems(self,itmi_stuff_mug_01,Npc_HasItems(self,itmi_stuff_mug_01));
Npc_RemoveInvItems(self,itmi_stuff_oldcoin_01,Npc_HasItems(self,itmi_stuff_oldcoin_01));
Npc_RemoveInvItems(self,itmi_stuff_oldcoin_02,Npc_HasItems(self,itmi_stuff_oldcoin_02));
Npc_RemoveInvItems(self,itmi_stuff_pan_01,Npc_HasItems(self,itmi_stuff_pan_01));
Npc_RemoveInvItems(self,itmi_stuff_pipe_01,Npc_HasItems(self,itmi_stuff_pipe_01));
Npc_RemoveInvItems(self,itmi_stuff_plate_01,Npc_HasItems(self,itmi_stuff_plate_01)); ////////////some traders have it
Npc_RemoveInvItems(self,itmi_stuff_silverware_01,Npc_HasItems(self,itmi_stuff_silverware_01));
Npc_RemoveInvItems(self,itmialarmhorn,Npc_HasItems(self,itmialarmhorn));
Npc_RemoveInvItems(self,itmibrush,Npc_HasItems(self,itmibrush));
Npc_RemoveInvItems(self,itmihammer,Npc_HasItems(self,itmihammer));
Npc_RemoveInvItems(self,itmilute,Npc_HasItems(self,itmilute));
Npc_RemoveInvItems(self,itmiscoop,Npc_HasItems(self,itmiscoop));
Npc_RemoveInvItems(self,itmistomper,Npc_HasItems(self,itmistomper));
Npc_RemoveInvItems(self,itmiwedel,Npc_HasItems(self,itmiwedel));

////////Food
Npc_RemoveInvItems(self,itat_meatbug_01,Npc_HasItems(self,itat_meatbug_01));
Npc_RemoveInvItems(self,itfo_mutton_01,Npc_HasItems(self,itfo_mutton_01));
Npc_RemoveInvItems(self,itfo_plants_mushroom_01,Npc_HasItems(self,itfo_plants_mushroom_01));
Npc_RemoveInvItems(self,itfo_plants_mushroom_02,Npc_HasItems(self,itfo_plants_mushroom_02));
Npc_RemoveInvItems(self,itfo_wineberrys_01,Npc_HasItems(self,itfo_wineberrys_01));
Npc_RemoveInvItems(self,itfocheese,Npc_HasItems(self,itfocheese));
Npc_RemoveInvItems(self,itfocrawlersoup,Npc_HasItems(self,itfocrawlersoup));
Npc_RemoveInvItems(self,itfoloaf,Npc_HasItems(self,itfoloaf));
Npc_RemoveInvItems(self,itfomeatbugragout,Npc_HasItems(self,itfomeatbugragout));
Npc_RemoveInvItems(self,itfomuttonraw,Npc_HasItems(self,itfomuttonraw));
Npc_RemoveInvItems(self,itfomutton,Npc_HasItems(self,itfomutton));
Npc_RemoveInvItems(self,itforice,Npc_HasItems(self,itforice));
Npc_RemoveInvItems(self,itfosoup,Npc_HasItems(self,itfosoup));
Npc_RemoveInvItems(self,itfowine,Npc_HasItems(self,itfowine));

////////common shitty human weapon
Npc_RemoveInvItems(self,ItMwPickaxe,Npc_HasItems(self,ItMwPickaxe)); //////Kilof

Npc_RemoveInvItems(self,ItMwPickaxe,Npc_HasItems(self,ItMw_1H_Hatchet_01));
Npc_RemoveInvItems(self,ItMwPickaxe,Npc_HasItems(self,Itmw_1h_club_01));
Npc_RemoveInvItems(self,ItMwPickaxe,Npc_HasItems(self,Itmw_1H_Mace_Light_01));
Npc_RemoveInvItems(self,ItMwPickaxe,Npc_HasItems(self,ItMw_1h_Sword_01));
Npc_RemoveInvItems(self,ItMwPickaxe,Npc_HasItems(self,altesschwert));
Npc_RemoveInvItems(self,ItMwPickaxe,Npc_HasItems(self,ItMw_1H_Poker_01));
Npc_RemoveInvItems(self,ItMwPickaxe,Npc_HasItems(self,ItMw_1H_Poker_01));
Npc_RemoveInvItems(self,ItMwPickaxe,Npc_HasItems(self,ItMw_1H_Poker_01));
};

To co jest wyżej wkleiłem zwyczajowo do pliku "B_InExtremo.d" w Gothic\_work\DATA\scripts\Content\Story\B.

Potem każdemu z handlarzy w Gothic I w odpowiednim pliku dialogowym znajdującym się w Gothic\_work\DATA\Scripts\Content\Story\MISSIONS dokleiłem wywoływanie funkcji "b_clearjunktradeinv" po wybraniu opcji "KONIEC" (w sensie koniec rozmowy a koniec handlu). Na przykład w DIA_Stt_311_Fisk.d

Spoiler
instance  Stt_311_Fisk_Exit (C_INFO)
{
   npc         = Stt_311_Fisk;
   nr         = 999;
   condition   = Stt_311_Fisk_Exit_Condition;
   information   = Stt_311_Fisk_Exit_Info;
   permanent   = 1;
   description = DIALOG_ENDE;
};                       

FUNC int  Stt_311_Fisk_Exit_Condition()
{
   return 1;
};

FUNC VOID  Stt_311_Fisk_Exit_Info()
{
   AI_StopProcessInfos   (self);
   b_clearjunktradeinv   (self);
};

Tak trzeba zrobić dla wszystkich kupców. Listę wszystkich handlarzy mamy choćby na stronie Gothicpedii  https://gothic.fandom.com/pl/wiki/Handlarze_w_Gothic

Gotowe. Teraz po zakończeniu handlu a następnie po wyjściu z rozmowy z kupcem cały szrot jest usuwany a my możemy elegancko przeglądać asortyment kupca :)

12
Dziękuję bardzo za pomoc. Widocznie prośba o przekopiowanie stosownej części z jednego z plików .PML Gothic\_work\Tools\data żeby kolejni ludzie nie musieli się z osobna pierdzielić się z ustawianiem parametrów wody najwyraźniej była proszeniem o zbyt wiele dlatego jakby ktoś w przyszłości potrzebował się posiłkować gotowcem przy ustawianiu tych parametrów to wrzucam zawartość swojego pliku "WATER2.PML". Jeżeli ktoś chce to może w oparciu o to ustawić sobie parametry wody w Spacerze. Parametr "texAniMapDir" w tych teksturach został wzięty stąd https://themodders.org/index.php?topic=49.msg407#msg407 z pewnymi zmianami:
Spoiler
- uzupełniłem chyba dwie tekstury wody, których nie było na tamtej liście (na pewno OWODSEA2SWAMP);
- przyspieszyłem trochę wodę z wodospadu bo na oko w wersji steamowej Gothica była chyba szybsza;
- OWODWFALL_HITSURFACE ustaliłem metodą prób i błędów;
- OWODWFALL_STONE wyłączyłem (zastąpiłem niewidzialną teksturą) bo ustalanie tego metodą prób i tak zżarło mi zbyt dużo czasu.

Woda płynie i da się w niej pływać ale nie jest przezroczysta, bo nie umiałem tego ustawić więc z lądu nie zobaczysz tego co jest pod wodą. Jeżeli wiesz jak to naprawić to możesz się tym podzielić choćby w tym temacie by ktoś inny się z tym nie musiał pierdzielić.

UWAGA: Nie polecam bezpośredniej przeklejki bo te tekstury najpierw trzeba przenieść do innego filtra. Najłatwiej to zrobić w Spacerze. W tym poście masz to wszystko ładnie opisane: https://themodders.org/index.php?topic=49.msg40990#msg40990 Żeby woda płynęła i by można było w niej pływać musisz sobie poustawiać parametr "texAniMapDir" (z cyferkami) oraz parametr "texAniMapMode".

Jeżeli chodzi o texAniMapMode to w pliku .pml będziesz miał "texAniMapMode=enum:0" lub "texAniMapMode=enum:1", ale w Spacerze zamiast 0 i 1 będziesz miał "NONE" I "LINEAR". "NONE" ustawiasz w jeziorach i tam gdzie woda jest stojąca. "LINEAR" ustawiasz tam gdzie woda ma płynąć.

UWAGA 2: Poniższe parametry dotyczą Gothica 1.

Zawartość pliku WATER2.PML
Spoiler

ZenGin Archive
ver 1
zCArchiverGeneric
ASCII
saveGame 0
date 15.6.2025 16:28:37
user ///////
END
objects 10       
END

[% zCMaterial 17408 0]
name=string:OWODWATSTOP
matGroup=enum:5
color=color:72 93 101 255
smoothAngle=float:60
texture=string:OWODSEA_A0.TGA
texScale=string:256 256
texAniFPS=float:0
texAniMapMode=enum:0
texAniMapDir=string:0 0
noCollDet=bool:0
noLightmap=bool:0
lodDontCollapse=bool:0
detailObject=string:
defaultMapping=rawFloat:2.34375 2.34375
[]
[% zCMaterial 17408 1]
name=string:OWODWFALL2SEA
matGroup=enum:5
color=color:160 179 185 255
smoothAngle=float:60
texture=string:OWODWFALL2SEA_A0.TGA
texScale=string:256 256
texAniFPS=float:0
texAniMapMode=enum:1
texAniMapDir=string:0 -0.00029999999
noCollDet=bool:0
noLightmap=bool:0
lodDontCollapse=bool:0
detailObject=string:
defaultMapping=rawFloat:2.34375 2.34375
[]
[% zCMaterial 17408 2]
name=string:OWODWFALL
matGroup=enum:5
color=color:149 165 172 255
smoothAngle=float:60
texture=string:OWODWFALL_A0.TGA
texScale=string:512 512
texAniFPS=float:0
texAniMapMode=enum:1
texAniMapDir=string:0 -0.00089999998
noCollDet=bool:0
noLightmap=bool:0
lodDontCollapse=bool:0
detailObject=string:
defaultMapping=rawFloat:2.34375 2.34375
[]
[% zCMaterial 17408 3]
name=string:OWODWATSTAND
matGroup=enum:5
color=color:72 93 101 255
smoothAngle=float:60
texture=string:OWODWAT_A0.TGA
texScale=string:256 256
texAniFPS=float:0
texAniMapMode=enum:1
texAniMapDir=string:0 -2.9999999e-005
noCollDet=bool:0
noLightmap=bool:0
lodDontCollapse=bool:0
detailObject=string:
defaultMapping=rawFloat:2.34375 2.34375
[]
[% zCMaterial 17408 4]
name=string:OWODWFALL_HITSURFACE
matGroup=enum:5
color=color:48 50 52 255
smoothAngle=float:60
texture=string:OWODWFALL_HITSURFACE_A0.TGA
texScale=string:256 256
texAniFPS=float:0
texAniMapMode=enum:1
texAniMapDir=string:0.0099999998 0
noCollDet=bool:0
noLightmap=bool:0
lodDontCollapse=bool:0
detailObject=string:
defaultMapping=rawFloat:2.34375 2.34375
[]
[% zCMaterial 17408 5]
name=string:FLSWAMPLI         
matGroup=enum:5
color=color:35 39 19 255
smoothAngle=float:60
texture=string:SWAMP_A0.TGA
texScale=string:256 256
texAniFPS=float:0
texAniMapMode=enum:0
texAniMapDir=string:0 0
noCollDet=bool:0
noLightmap=bool:0
lodDontCollapse=bool:0
detailObject=string:
defaultMapping=rawFloat:2.34375 2.34375
[]
[% zCMaterial 17408 6]
name=string:OWODWFALL_STONE
matGroup=enum:5
color=color:249 250 250 255
smoothAngle=float:60
texture=string:MODIALPHA01.TGA
texScale=string:256 256
texAniFPS=float:0
texAniMapMode=enum:1
texAniMapDir=string:8 13.1
noCollDet=bool:0
noLightmap=bool:0
lodDontCollapse=bool:0
detailObject=string:
defaultMapping=rawFloat:2.34375 2.34375
[]
[% zCMaterial 17408 7]
name=string:OWODWFALLFASTWATER
matGroup=enum:5
color=color:149 165 172 255
smoothAngle=float:60
texture=string:OWODWFALL_A0.TGA
texScale=string:512 512
texAniFPS=float:0
texAniMapMode=enum:1
texAniMapDir=string:0 -0.00050000002
noCollDet=bool:0
noLightmap=bool:0
lodDontCollapse=bool:0
detailObject=string:
defaultMapping=rawFloat:2.34375 2.34375
[]
[% zCMaterial 17408 8]
name=string:OWODWATFAST
matGroup=enum:5
color=color:72 93 101 255
smoothAngle=float:60
texture=string:OWODWAT_A0.TGA
texScale=string:256 256
texAniFPS=float:0
texAniMapMode=enum:1
texAniMapDir=string:0 -0.00030000001
noCollDet=bool:0
noLightmap=bool:0
lodDontCollapse=bool:0
detailObject=string:
defaultMapping=rawFloat:2.34375 2.34375
[]
[% zCMaterial 17408 9]
name=string:OWODSEA2SWAMP
matGroup=enum:5
color=color:54 67 60 255
smoothAngle=float:60
texture=string:OWODSEA2SWAMP_A0.TGA
texScale=string:256 256
texAniFPS=float:0
texAniMapMode=enum:0
texAniMapDir=string:9.9999997e-005 0
noCollDet=bool:0
noLightmap=bool:0
lodDontCollapse=bool:0
detailObject=string:
defaultMapping=rawFloat:2.34375 2.34375
[]


Wrzucam jeszcze opracowanie dotyczące tego gdzie jaka tekstura występuje jakby ktoś potrzebował.

Spoiler
OWODWATFAST
Użycie:
- Wodospad do morza (przy Klasztorze Zmiennokształtnych)
- Fragment rzeki od Cmentarza Orków do wodospadów wpadających do jeziorka przy Obozie Bractwa

Parametry:
name:OWODWATFAST
matGroup:WATER
texture:OWODWAT_A0.TGA

OWODWATSTOP
Użycie:
- Morze
- Niebagienna część jeziorka z wodospadami koło Obozu Bractwa
- Jeziorko starej wieży Xardasa
- Jeziorko przy jaskini goblinów, które ukradły almanach
- Rzeka pod mostem goblinów, które ukradły almanach
- Jezioro z  chatą rybaków nieopodal Nowego Obozu (nieopodal terytorium orków)
- Jeziorko gdzie zaczynamy grę

Parametry:
name:OWODWATSTOP
matGroup:WATER
texture:OWODSEA_A0.TGA

FLSWAMPLI
Użycie:
- Bagienna część jeziorka z wodospadami koło Obozu Bractwa
- Zabagnione jeziorko koło wieży Xardasa
- Wszystkie bagna wokół Obozu Bractwa

Parametry:
name:FLSWAMPLI   
matGroup:WATER
texture:SWAMP_A0.TGA

OWODWFALL
Użycie:
- Trzy wodospady koło starej wieży Xardasa
- Duży wodospad przy jaskini goblinów, które ukradły almanach
- Wodospady koło Obozu Bractwa

Parametry:
name:OWODWFALL
matGroup:WATER
texture:OWODWFALL_A0.TGA

OWODWFALLFASTWATER
Użycie:
- Spływ od starej wieży Xardasa do Cmentarza Orków
- Mały wodospad przy jaskini goblinów, które ukradły almanach

Parametry:
name:OWODWFALLFASTWATER
matGroup:WATER
texture:OWODWFALL_A0.TGA

OWODSEA2SWAMP
Użycie:
- Strefa pośrednia między rodzajami wód na jeziorze przy Obozie Bractwa

Parametry:
name:OWODSEA2SWAMP
matGroup:WATER
texture:OWODSEA2SWAMP_A0.TGA

OWODWFALL2SEA
Użycie:
Wodospad do morza (nieopodal Klasztoru Zmiennokształtnych)

Parametry:
name:OWODWFALL2SEA
matGroup:WATER
texture:OWODWFALL2SEA_A0.TGA

OWODWFALL_HITSURFACE
Użycie:
Praktycznie każdy wodospad (plusk wody z wodospadu zderzającej się z wodą w rzece na dole)

Parametry:
name:OWODWFALL_HITSURFACE
matGroup: WATER
texture:OWODWFALL_HITSURFACE_A0.TGA

OWODWFALL_STONE
Użycie:
Woda z wodospadu obijająca się o skały (np. wodospady przy zatopionej wieży Xardasa)
W parametrze texture zamieniłem z "OWODWFALL_STONE_A0.TGA" (chyba) na "MODIALPHA01.TGA" żeby nie była widoczna w grze.

Parametry:
name:OWODWFALL_STONE
matGroup: WATER
texture:MODIALPHA01.TGA

13
Hejka, sposób użytkownika @Caesum z https://themodders.org/index.php?topic=49.msg40990#msg40990 bardzo fajnie działa. Jest tylko problem, że trzeba ustawić też inne parametry wody takie jak jej przezroczystość, prędkość nurtu, kierunek nurtu czy poprawne ustawienie pluskających elementów.

Przekopiowałem też rzeczy z wpisu @tunczyk cytowanego w poście https://themodders.org/index.php?topic=49.msg407#msg407
Porównując efekt z efektem z wersji steamowej Gothica zauważyłem, że w liście Tuńczyka woda w wodospadach jest ustawiona wolniej - więc nie wiem czy te parametry z listy były wzięte z gry czy autorskie, czy też może różnią się między wersjami gry. W liście Tuńczyka nie ma też kilku rodzajów wód (chyba brakuje OWODSEA2SWAMP) i przede wszystkim tych efektów pluskania przy wodospadach (OWODWFALL_STONE i OWODWFALL_HITSURFACE) a bardzo by się przydały. Dlatego prosiłbym o pomoc, bo nie udało mi się znaleźć tych pozostałych parametrów potrzebnych związanych z wodą. Próbowałem to podejrzeć w czystych plikach Gothica ale tam tych parametrów też nie było lub nie potrafiłem ich znaleźć.

Bardzo bym prosił jeżeli ktoś mógłby wkleić tu zawartość pliku .PML z Gothic\_work\Tools\Data zawierającego parametry wód. Chodzi o pierwszą część Gothica.

Potrzebuję parametrów następujących wód:

FLSWAMPLI

OWODSEA2SWAMP

OWODWATFAST

OWODWATSTAND

OWODWATSTOP

OWODWFALL

OWODWFALL2SEA

OWODWFALLFASTWATER


[efekty pluskania przy wodospadach]

OWODWFALL_HITSURFACE

OWODWFALL_STONE


Jak ktoś miałby analogiczny plik z Gothica 2 to też fajnie by było gdyby wrzucił jego zawartość, bo komuś kto chciałby modować drugą część gry też z pewnością by się przydały.

14
Dzięki. Nie wiedziałem, że w notepadzie++ istnieje opcja wyszukiwania po wszystkich plikach. To mi ułatwi wiele rzeczy :)

15
Chciałbym by po dialogu z NPC kończyła się gra i przenosiło nas do menu głównego. Chodzi mi o Gothic I.

Z tego co widziałem to na forum można znaleźć opis, który ma zastosowanie do Gothica II ale w Gothicu I nie działa.


PS: Byłbym też wdzięczny gdyby ktoś miał namiary na plik w skryptach Gothic I, który odpowiada za odpalenie oryginalnego zakończenia bo trochę się naszukałem i nie mogę znaleźć.

16
Wrzucam bo sam się tego mocno naszukałem, więc może komuś oszczędzę tych poszukiwań. Lista jakby co nie moja. Niektórych plików muzycznych brakuje. Rzeczy, których nie mogłem znaleźć w folderach Gothica i Gothica II zaznaczyłem na żółto.


Gothic
Spoiler
Gothic\_work\DATA\Music

01 Title Theme.mp3
Menu.sgt

02 Valley of Mines.mp3
OW_Day_Std.sgt

03 Old Camp.mp3
OC_Day_Std.sgt

04 Old Camp (Combat).mp3
OC_Day_Fgt.sgt

05 Ore Barons.mp3
BAN_Day_Std.sgt

06 Prison Colony.mp3
CAM_Day_Std.sgt

07 Prison Colony (Night).mp3
CAM_Ngt_Std.sgt

08 Prison Colony (Engagement).mp3
CAM_Day_Thr.sgt

09 Prison Colony (Combat).mp3
CAM_Day_Fgt.sgt

10 New Camp.mp3
NCI_Day_Std.sgt

11 New Camp (Combat).mp3
NCI_Day_Fgt.sgt

12 Sect Camp.mp3
PSI_Day_std.sgt

13 Sect Camp (Night).mp3
PSI_Ngt_Std.sgt

14 Sect Camp (Engagement).mp3
PSI_Day_Thr.sgt

15 Sect Camp (Combat).mp3
PSI_Day_Fgt.sgt

16 Old Mine.mp3
OLM_Day_Std.sgt

17 Old Mine (Engagement).mp3
OLM_Day_Thr.sgt

18 Old Mine (Combat).mp3
OLM_Day_Fgt.sgt

19 Undead.mp3
FOC_Day_Std.sgt

20 Orc Settlement.mp3
ORC_Day_Std.sgt

21 Temple of the Sleeper.mp3
OGY_Day_Std.sgt

22 Temple of the Sleeper (Combat).mp3
OGY_Day_Fgt.sgt

23 Gothic Theme (Install).mp3
(brak pliku)



Gothic II

Spoiler
Gothic II\_work\data\Music

01 Opening Theme.mp3.[/b]
wav played at game start
(brak pliku)

02 Title Theme.mp3
Gamestart.sgt

03 Chapter Theme.mp3
CHAPTER_01.WAV

04 Xardas' Tower.mp3
XT_DayStd.sgt

05 Khorinis.mp3
Default.sgt

06 Lobart's Farm.mp3
LOB_DayStd.sgt

07 City of Khorinis.mp3
KH_DayStd.sgt

08 Khorinis Barracks.mp3
KAS_DayStd.sgt

09 City of Khorinis (Combat).mp3
KH_DayFgt.sgt

10 The Lighthouse.mp3
LEU_DayStd.sgt

11 Khorinis (Alternate).mp3
NW_DayStd_A0.sgt

12 Bandit Caves.mp3
BAN_DayStd.sgt

13 Bandit Caves (Combat).mp3
BAN_DayFgt.sgt

14 The Woods.mp3
WOO_DayStd.sgt

15 The Woods (Engagement).mp3
WOO_DayThr.sgt

16 The Woods (Combat).mp3
WOO_DayFgt.sgt

17 The Monastery of Innos.mp3
MO_DayStd.sgt

18 Fire Mages.mp3
MI_DayStd.sgt

19 Cemetary.mp3
FRI_DayStd.sgt

20 Temple Ruins.mp3
MAY_DayStd.sgt

21 Temple Ruins (Combat).mp3
MAY_DayFgt.sgt

22 Pass to the Valley of Mines.mp3
OWP_DayStd.sgt

23 Pass to the Valley of Mines (Combat).mp3
OWP_DayFgt.sgt

24 Valley of Mines.mp3
OWD_DayStd.sgt

25 The Dragons.mp3
DLC_DayStd.sgt

26 The Dragons (Combat).mp3
DLC_DayFgt.sgt

27 Khorinis (Alternate II).mp3
NW_DayStd_A1.sgt

28 Khorinis (Engagement).mp3
NW_DayThr.sgt

29 Khorinis (Combat).mp3
NW_DayFgt.sgt

30 Khorinis (Alternate III).mp3
NW_DayStd.sgt

31 Khorinis Harbor.mp3
PIE_DayStd.sgt

32 The Halls of Irdorath.mp3
DI_DayStd.sgt

33 Gothic II Theme (Install).mp3
.wav played during install
(brak pliku)

34 Love Theme (Piano).mp3
_Love.sty (test1)



Gothic II: Night of the Raven
Spoiler
Gothic II\_work\data\Music

01 Opening Theme.mp3 .
wav played at game start
(brak pliku)

02 Opening The Portal.mp3
.wav played upon opening portal to Jharkendar
(brak pliku)

03 Jharkendar Caves.mp3
BIB_Day_Std.sgt

04 Water Mages.mp3
AWC_Day_Std.sgt

05 Jharkendar.mp3
ADW_Day_Std.sgt

06 Jharkendar (Combat).mp3
ADW_Day_Fgt.sgt

07 Pirate Camp.mp3
PIR_Day_Std.sgt

08 The Canyon.mp3
CAN_Day_Std.sgt

09 The Swamp.mp3
SWP_Day_Std.sgt

10 Jharkendar Ruins.mp3
STO_Day_Std.sgt

11 Bandit Camp.mp3
BDT_Day_Std.sgt

12 The Temple.mp3
ADT_Day_Std.sgt

13 Raven.mp3
SHO_Day_Std.sgt

14 Raven (Combat).mp3
SHO_Day_Fgt.sgt


Źródło: opracował użytkownik Speon z portalu World of Gothic w 2006 roku, https://forum.worldofplayers.de/forum/threads/150061-Music-Soundtrack-of-Gothic?p=2538417&viewfull=1#post2538417

17
Skrypty / Wpis do dziennika wraz z tytułem zadania.
« dnia: 2025-06-02, 00:30 »
Podrzucam odrobinę przerobioną wersję skryptu autorstwa Vanariusa do Gothica I, bo skrypt z pierwszego postu w tym temacie dotyczy Gothica 2 i pierwsza część Gothica go nie zasysa.


Wpis do dziennika wraz z tytułem zadania - wersja do Gothic I

Tutaj trzeba wejść do pliku B_Functions.d w folderze Gothic\_work\DATA\scripts\Content\AI\AI_Intern i tam podmienić istniejącą funkcję B_LogEntry na:

var int Move_Entry;

func void B_LogEntry (var string topic, var string entry)
{
Log_AddEntry (topic, entry);

var string txt;

txt = ConcatStrings ("Nowy wpis do dziennika (", topic); //początek tekstu, który ma się wyświetlać w tym przypadku jest to "Nowy wpis do dziennika (" Pamiętać żeby dać ten nawias bo wtedy efekt będzie brzydki.
txt = ConcatStrings (txt, ")"); //tutaj tylko zamykamy nawias który rozpoczęliśmy na górze.

if (Move_Entry == FALSE)
{
PrintScreen (/*PRINT_NewLogEntry*/txt, -1, _YPOS_MESSAGE_LOGENTRY, "FONT_OLD_10_WHITE.TGA",_TIME_MESSAGE_GIVEN);

Move_Entry = TRUE;
}
else
{
Move_Entry = FALSE;

PrintScreen (/*PRINT_NewLogEntry*/txt, -1, _YPOS_MESSAGE_LOGENTRY - 5, "FONT_OLD_10_WHITE.TGA",_TIME_MESSAGE_GIVEN);
};

Snd_Play ("LogEntry");
};

18
Dużo filozofii tutaj nie ma. Skopiowałem funkcję b_clearruneinv z Gothica II, podmieniłem czary i zrobiłem by się aktywowała w momencie gdy postać jest nieprzytomna/zabita. Dzięki temu otrzymuje się taki efekt jak w Gothic II - np. jak przy zabiciu poszukiwacza, któremu nie da się zabrać zaklęć.

Przydatne jeżeli ktoś dodaje do swojej modyfikacji do Gothica I sporo przeciwników posługujących się runami i nie chce by potem gracz sprzedawał je handlarzom. W Gothic I runy są dość drogie, więc przy większej liczbie przeciwników postać dostałaby dość dużego zastrzyku magicznej rudy.

Wklejam gotowca dla oszczędności sił i czasu, bo nie ma sensu by każdy kolejny modder do swojego projektu wykonywał ten skrypt od nowa.

func void b_clearruneinv(var C_NPC slf)
{
var C_NPC her;
her = Hlp_GetNpc(pc_hero);
if(Hlp_GetInstanceID(self) != Hlp_GetInstanceID(her))
{
Npc_RemoveInvItems(slf,ItArRuneLight,Npc_HasItems(slf,ItArRuneLight));
Npc_RemoveInvItems(slf,ItArRuneFirebolt,Npc_HasItems(slf,ItArRuneFirebolt));
Npc_RemoveInvItems(slf,ItArRuneFireball,Npc_HasItems(slf,ItArRuneFireball));
Npc_RemoveInvItems(slf,ItArRuneFirestorm,Npc_HasItems(slf,ItArRuneFirestorm));
Npc_RemoveInvItems(slf,ItArRuneFireRain,Npc_HasItems(slf,ItArRuneFireRain));
Npc_RemoveInvItems(slf,ItArRuneHeal,Npc_HasItems(slf,ItArRuneHeal));
Npc_RemoveInvItems(slf,ItArRuneChainLightning,Npc_HasItems(slf,ItArRuneChainLightning));
Npc_RemoveInvItems(slf,ItArRuneThunderbolt,Npc_HasItems(slf,ItArRuneThunderbolt));
Npc_RemoveInvItems(slf,ItArRuneThunderball,Npc_HasItems(slf,ItArRuneThunderball));
Npc_RemoveInvItems(slf,ItArRuneIceCube,Npc_HasItems(slf,ItArRuneIceCube));
Npc_RemoveInvItems(slf,ItArRuneIceWave,Npc_HasItems(slf,ItArRuneIceWave));
Npc_RemoveInvItems(slf,ItArRuneDestroyUndead,Npc_HasItems(slf,ItArRuneDestroyUndead));
Npc_RemoveInvItems(slf,ItArRuneWindfist,Npc_HasItems(slf,ItArRuneWindfist));
Npc_RemoveInvItems(slf,ItArRuneStormfist,Npc_HasItems(slf,ItArRuneStormfist));
Npc_RemoveInvItems(slf,ItArRuneTelekinesis,Npc_HasItems(slf,ItArRuneTelekinesis));
Npc_RemoveInvItems(slf,ItArRuneCharm,Npc_HasItems(slf,ItArRuneCharm));
Npc_RemoveInvItems(slf,ItArRuneSleep,Npc_HasItems(slf,ItArRuneSleep));
Npc_RemoveInvItems(slf,ItArRunePyrokinesis,Npc_HasItems(slf,ItArRunePyrokinesis));
Npc_RemoveInvItems(slf,ItArRuneControl,Npc_HasItems(slf,ItArRuneControl));
Npc_RemoveInvItems(slf,ItArRuneBreathOfDeath,Npc_HasItems(slf,ItArRuneBreathOfDeath));
};
};

To co jest wyżej wkleiłem zwyczajowo do pliku "B_InExtremo.d" w Gothic\_work\DATA\scripts\Content\Story\B.

By funkcja się wywoływała wklejasz B_ClearRuneInv(self); w plikach "ZS_Dead.d" i "ZS_Unconscious.d". Oba pliki znajdują się w Gothic\_work\DATA\scripts\Content\AI\ZS_Human.

W pliku "ZS_Dead.d" możesz wkleić B_ClearRuneInv(self); pod B_GiveDeathInv();, zaś w ZS_Unconscious.d" tuż poniżej self.aivar[AIV_PLUNDERED] = FALSE;

Te wycinki powinny wyglądać wówczas tak:

W "ZS_Dead.d":

B_GiveDeathInv();
B_ClearRuneInv(self); //klaue alle runen!!

W "ZS_Unconscious.d"

self.aivar[AIV_PLUNDERED] = FALSE;
B_ClearRuneInv(self);//Hoshi, damit der Player keine Runen findet!

Gotowe!

19
Mam pewien problem. Próbuję dodać oCTriggerChangeLevel, który na początku gry byłby nieaktywny i aktywowałby się dopiero w późniejszym rozdziale gry.

Dodałem w Spacerze stosowny oCTriggerChangeLevel i ustawiłem (też w Spacerze) "StartEnable:False".

Pytanie:
Co muszę wpisać by ten "uśpiony" changelevel się "obudził"?
Mam na myśli: co musiałbym dopisać przykładowo w takim pliku "Gothic\_work\DATA\scripts\Content\Story\CHAPTERS\B_Story_UrizielLoaded.d" by do zadziałało na changelevel.


Korzystając też z okazji chciałbym też zadać drugie pytanie:
Czy da się z poziomu skryptów zmienić "showVisual:FALSE" na "showVisual:TRUE"?

20
Problem rozwiązany.

Gdy wszystkie funkcje wklepałem i próbowałem reparsować, to wywalały błędy Undefined function
np. "U:PAR Undefined function: B_GETLEARNCOSTATTRIBUTE (line 56)" chociaż wszystkie funkcje znajdowały się już przecież w plikach.
Kolejno więc przesuwałem te "niezdefiniowane funkcje" wyżej w pliku tekstowym, by były bezpośrednio nad funkcją, w której doszło do "nierozpoznania".


Dla najbardziej leniwych wrzucam gotowca do przeklejki:

Jak chcecie sobie przeszczepić system z Gothic 2 NK do Gothic 1 to musicie to zrobić w kilku krokach:

1. Przekopiujcie te funkcje np. do pliku "Gothic\_work\DATA\scripts\Content\Story\B\B_InExtremo.d". Najlepiej na sam spód:

//////////////////////////////////////////////////////////////////////////
// NOTR
// ===============
//
//////////////////////////////////////////////////////////////////////////

func int B_GetLearnCostTalent(var C_Npc oth,var int talent,var int skill)
{
   var int kosten;
   kosten = 0;
   if(talent == NPC_TALENT_1H)
   {
      if(Npc_GetTalentValue(hero,NPC_TALENT_1H) >= 90)
      {
         kosten = 4;
      }
      else if(Npc_GetTalentValue(hero,NPC_TALENT_1H) >= 60)
      {
         kosten = 3;
      }
      else if(Npc_GetTalentValue(hero,NPC_TALENT_1H) >= 30)
      {
         kosten = 2;
      }
      else
      {
         kosten = 1;
      };
      kosten = kosten * skill;
   };
   if(talent == NPC_TALENT_2H)
   {
      if(Npc_GetTalentValue(hero,NPC_TALENT_2H) >= 90)
      {
         kosten = 4;
      }
      else if(Npc_GetTalentValue(hero,NPC_TALENT_2H) >= 60)
      {
         kosten = 3;
      }
      else if(Npc_GetTalentValue(hero,NPC_TALENT_2H) >= 30)
      {
         kosten = 2;
      }
      else
      {
         kosten = 1;
      };
     
      kosten = kosten * skill;
   };
   if(talent == NPC_TALENT_BOW)
   {
      if(Npc_GetTalentValue(hero,NPC_TALENT_BOW) >= 90)
      {
         kosten = 4;
      }
      else if(Npc_GetTalentValue(hero,NPC_TALENT_BOW) >= 60)
      {
         kosten = 3;
      }
      else if(Npc_GetTalentValue(hero,NPC_TALENT_BOW) >= 30)
      {
         kosten = 2;
      }
      else
      {
         kosten = 1;
      };
     
      kosten = kosten * skill;
   };
   if(talent == NPC_TALENT_CROSSBOW)
   {
      if(Npc_GetTalentValue(hero,NPC_TALENT_CROSSBOW) >= 90)
      {
         kosten = 4;
      }
      else if(Npc_GetTalentValue(hero,NPC_TALENT_CROSSBOW) >= 60)
      {
         kosten = 3;
      }
      else if(Npc_GetTalentValue(hero,NPC_TALENT_CROSSBOW) >= 30)
      {
         kosten = 2;
      }
      else
      {
         kosten = 1;
      };
     
      kosten = kosten * skill;
   };   
   return kosten;
};

func void B_SetFightSkill(var C_Npc slf,var int talent,var int percent)
{
   if(talent == NPC_TALENT_1H)
   {
      if(Npc_GetTalentValue(hero,NPC_TALENT_1H) >= 0)
      {
         Npc_SetTalentSkill(slf,NPC_TALENT_1H,0);
      };
      if(Npc_GetTalentValue(hero,NPC_TALENT_1H) >= 30)
      {
         Npc_SetTalentSkill(slf,NPC_TALENT_1H,1);
      };
      if(Npc_GetTalentValue(hero,NPC_TALENT_1H) >= 60)
      {
         Npc_SetTalentSkill(slf,NPC_TALENT_1H,2);
      };
   };
   if(talent == NPC_TALENT_2H)
   {
      if(Npc_GetTalentValue(hero,NPC_TALENT_2H) >= 0)
      {
         Npc_SetTalentSkill(slf,NPC_TALENT_2H,0);
      };
      if(Npc_GetTalentValue(hero,NPC_TALENT_2H) >= 30)
      {
         Npc_SetTalentSkill(slf,NPC_TALENT_2H,1);
      };
      if(Npc_GetTalentValue(hero,NPC_TALENT_2H) >= 60)
      {
         Npc_SetTalentSkill(slf,NPC_TALENT_2H,2);
      };
   };
   if(talent == NPC_TALENT_BOW)
   {
      if(Npc_GetTalentValue(hero,NPC_TALENT_BOW) >= 0)
      {
         Npc_SetTalentSkill(slf,NPC_TALENT_BOW,0);
      };
      if(Npc_GetTalentValue(hero,NPC_TALENT_BOW) >= 30)
      {
         Npc_SetTalentSkill(slf,NPC_TALENT_BOW,1);
      };
      if(Npc_GetTalentValue(hero,NPC_TALENT_BOW) >= 60)
      {
         Npc_SetTalentSkill(slf,NPC_TALENT_BOW,2);
      };
   };
   if(talent == NPC_TALENT_CROSSBOW)
   {
      if(Npc_GetTalentValue(hero,NPC_TALENT_CROSSBOW) >= 0)
      {
         Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,0);
      };
      if(Npc_GetTalentValue(hero,NPC_TALENT_CROSSBOW) >= 30)
      {
         Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,1);
      };
      if(Npc_GetTalentValue(hero,NPC_TALENT_CROSSBOW) >= 60)
      {
         Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,2);
      };
   };
};

func int B_TeachFightTalentPercent(var C_Npc slf,var C_Npc oth,var int talent,var int percent,var int teacherMAX)
{
   var string concatText;
   var int kosten;
   var int realHitChance;
   kosten = B_GetLearnCostTalent(oth,talent,1) * percent;
   if((talent != NPC_TALENT_1H) && (talent != NPC_TALENT_2H) && (talent != NPC_TALENT_BOW) && (talent != NPC_TALENT_CROSSBOW))
   {
      Print("*** Błąd: Zły parametr ***");
      return FALSE;
   };
   if(talent == NPC_TALENT_1H)
   {
      realHitChance = Npc_GetTalentValue(hero,NPC_TALENT_1H);
   }
   else if(talent == NPC_TALENT_2H)
   {
      realHitChance = Npc_GetTalentValue(hero,NPC_TALENT_2H);
   }
   else if(talent == NPC_TALENT_BOW)
   {
      realHitChance = Npc_GetTalentValue(hero,NPC_TALENT_BOW);
   }
   else if(talent == NPC_TALENT_CROSSBOW)
   {
      realHitChance = Npc_GetTalentValue(hero,NPC_TALENT_CROSSBOW);
   };
   if(realHitChance >= teacherMAX)
   {
      concatText = ConcatStrings("Maksimum dla tego nauczyciela wynosi ",IntToString(teacherMAX));
      PrintScreen(concatText,-1,-1,"FONT_OLD_20_WHITE.TGA",2);
      B_Say(slf,oth,"$NOLEARNYOUREBETTER");
      return FALSE;
   };
   if((realHitChance + percent) > teacherMAX)
   {
      concatText = ConcatStrings("Maksimum dla tego nauczyciela wynosi ",IntToString(teacherMAX));
      PrintScreen(concatText,-1,-1,"FONT_OLD_20_WHITE.TGA",2);
      B_Say(slf,oth,"$NOLEARNOVERPERSONALMAX");
      return FALSE;
   };
   if(oth.lp < kosten)
   {
      PrintScreen("Za mało punktów umiejętności!",-1,-1,"FONT_OLD_20_WHITE.TGA",2);
      B_Say(slf,oth,"$NOLEARNNOPOINTS");
      return FALSE;
   };
   oth.lp = oth.lp - kosten;
   if(talent == NPC_TALENT_1H)
   {
      Npc_SetTalentValue(hero, NPC_TALENT_1H, Npc_GetTalentValue(hero, NPC_TALENT_1H)+percent);
      if(Npc_GetTalentValue(hero,NPC_TALENT_1H) >= (Npc_GetTalentValue(hero,NPC_TALENT_2H) +30))
      {
         Npc_SetTalentValue(hero, NPC_TALENT_2H, Npc_GetTalentValue(hero, NPC_TALENT_2H)+percent);
         PrintScreen("Trening: posługiwanie się bronią jedno- i dwuręczną", -1,10,"FONT_OLD_20_WHITE.TGA",2);
         B_SetFightSkill(hero,NPC_TALENT_2H,percent);
      }
      else
      {
         PrintScreen("Trening: posługiwanie się bronią jednoręczną", -1,10,"FONT_OLD_20_WHITE.TGA",2);
      };
      B_SetFightSkill(hero,talent,percent);
      return TRUE;
   };
   if(talent == NPC_TALENT_2H)
   {
      Npc_SetTalentValue(hero, NPC_TALENT_2H, Npc_GetTalentValue(hero, NPC_TALENT_2H)+percent);   
      if(Npc_GetTalentValue(hero,NPC_TALENT_2H) >= (Npc_GetTalentValue(hero,NPC_TALENT_1H) +30))   
      {
         Npc_SetTalentValue(hero, NPC_TALENT_1H, Npc_GetTalentValue(hero, NPC_TALENT_1H)+percent);
         B_SetFightSkill(hero,NPC_TALENT_1H,percent);
         PrintScreen   ("Trening: posługiwanie się bronią dwu- i jednoręczną", -1,10,"FONT_OLD_20_WHITE.TGA",2);
      }
      else
      {
         PrintScreen   ("Trening: posługiwanie się bronią dwuręczną", -1,10,"FONT_OLD_20_WHITE.TGA",2);
      };
      B_SetFightSkill(hero,talent,percent);
      return TRUE;
   };
   if(talent == NPC_TALENT_BOW)
   {
      Npc_SetTalentValue(hero, NPC_TALENT_BOW, Npc_GetTalentValue(hero, NPC_TALENT_BOW)+percent);
      if(Npc_GetTalentValue(hero,NPC_TALENT_BOW) >= (Npc_GetTalentValue(hero,NPC_TALENT_CROSSBOW) +30))   
      {
         Npc_SetTalentValue(hero, NPC_TALENT_CROSSBOW, Npc_GetTalentValue(hero, NPC_TALENT_CROSSBOW)+percent);
         PrintScreen   ("Trening: posługiwanie się łukiem i kuszą", -1,10,"FONT_OLD_20_WHITE.TGA",2);
         B_SetFightSkill(hero,NPC_TALENT_CROSSBOW,percent);
      }
      else
      {
         PrintScreen   ("Trening: posługiwanie się łukiem", -1,10,"FONT_OLD_20_WHITE.TGA",2);
      };
      B_SetFightSkill(hero,talent,percent);
      return TRUE;
   };
   if(talent == NPC_TALENT_CROSSBOW)
   {
      Npc_SetTalentValue(hero, NPC_TALENT_CROSSBOW, Npc_GetTalentValue(hero, NPC_TALENT_CROSSBOW)+percent);
      if(Npc_GetTalentValue(hero,NPC_TALENT_CROSSBOW) >= (Npc_GetTalentValue(hero,NPC_TALENT_BOW) +30))   
      {
         Npc_SetTalentValue(hero, NPC_TALENT_BOW, Npc_GetTalentValue(hero, NPC_TALENT_BOW)+percent);
         B_SetFightSkill(hero,NPC_TALENT_BOW,percent);
         PrintScreen   ("Trening: posługiwanie się kuszą i łukiem", -1,10,"FONT_OLD_20_WHITE.TGA",2);         
      }
      else
      {
         PrintScreen   ("Trening: posługiwanie się kuszą", -1,10,"FONT_OLD_20_WHITE.TGA",2);
      };
      B_SetFightSkill(hero,talent,percent);
      return TRUE;
   };
};

func int B_GetLearnCostAttribute(var C_Npc oth,var int attribut)
{
   var int kosten;
   kosten = 0;
   if(attribut == ATR_STRENGTH)
   {
      if(oth.attribute[ATR_STRENGTH] >= 120)
      {
         kosten = 5;
      }
      else if(oth.attribute[ATR_STRENGTH] >= 90)
      {
         kosten = 4;
      }
      else if(oth.attribute[ATR_STRENGTH] >= 60)
      {
         kosten = 3;
      }
      else if(oth.attribute[ATR_STRENGTH] >= 30)
      {
         kosten = 2;
      }
      else
      {
         kosten = 1;
      };
   };
   if(attribut == ATR_DEXTERITY)
   {
      if(oth.attribute[ATR_DEXTERITY] >= 120)
      {
         kosten = 5;
      }
      else if(oth.attribute[ATR_DEXTERITY] >= 90)
      {
         kosten = 4;
      }
      else if(oth.attribute[ATR_DEXTERITY] >= 60)
      {
         kosten = 3;
      }
      else if(oth.attribute[ATR_DEXTERITY] >= 30)
      {
         kosten = 2;
      }
      else
      {
         kosten = 1;
      };
   };
   if(attribut == ATR_MANA_MAX)
   {
      if(oth.attribute[ATR_MANA_MAX] >= 120)
      {
         kosten = 5;
      }
      else if(oth.attribute[ATR_MANA_MAX] >= 90)
      {
         kosten = 4;
      }
      else if(oth.attribute[ATR_MANA_MAX] >= 60)
      {
         kosten = 3;
      }
      else if(oth.attribute[ATR_MANA_MAX] >= 30)
      {
         kosten = 2;
      }
      else
      {
         kosten = 1;
      };
   };
   return kosten;
};

func void B_RaiseAttribute_Gothic2(var C_Npc oth,var int attrib,var int points)
{
   var string concatText;
   if(attrib == ATR_STRENGTH)
   {
      oth.attribute[ATR_STRENGTH] = oth.attribute[ATR_STRENGTH] + points;
      concatText = ConcatStrings(NAME_RaiseStrength,IntToString(points));
      PrintScreen(concatText,-1,-1,"FONT_OLD_20_WHITE.TGA",4);
   };
   if(attrib == ATR_DEXTERITY)
   {
      oth.attribute[ATR_DEXTERITY] = oth.attribute[ATR_DEXTERITY] + points;
      concatText = ConcatStrings(NAME_RaiseDexterity,IntToString(points));
      PrintScreen(concatText,-1,-1,"FONT_OLD_20_WHITE.TGA",4);
   };
   if(attrib == ATR_MANA_MAX)
   {
      oth.attribute[ATR_MANA_MAX] = oth.attribute[ATR_MANA_MAX] + points;
      concatText = ConcatStrings(NAME_RaiseManaMax,IntToString(points));
      PrintScreen(concatText,-1,-1,"FONT_OLD_20_WHITE.TGA",4);
   };
   if(attrib == ATR_HITPOINTS_MAX)
   {
      oth.attribute[ATR_HITPOINTS_MAX] = oth.attribute[ATR_HITPOINTS_MAX] + points;
      concatText = ConcatStrings(NAME_RaiseHealthMax,IntToString(points));
      PrintScreen(concatText,-1,-1,"FONT_OLD_20_WHITE.TGA",4);
   };
   //B_RaiseRealAttributeLearnCounter(oth,attrib,points);
};

func int B_TeachAttributePoints(var C_Npc slf,var C_Npc oth,var int attrib,var int points,var int teacherMAX)
{
   var string concatText;
   var int kosten;
   var int realAttribute;
   kosten = B_GetLearnCostAttribute(oth,attrib) * points;
   if((attrib != ATR_STRENGTH) && (attrib != ATR_DEXTERITY) && (attrib != ATR_MANA_MAX))
   {
      Print("*** Błąd: Zły parametr ***");
      return FALSE;
   };
   if(attrib == ATR_STRENGTH)
   {
      realAttribute = oth.attribute[ATR_STRENGTH];
   }
   else if(attrib == ATR_DEXTERITY)
   {
      realAttribute = oth.attribute[ATR_DEXTERITY];
   }
   else if(attrib == ATR_MANA_MAX)
   {
      realAttribute = oth.attribute[ATR_MANA_MAX];
   };
   if(realAttribute >= teacherMAX)
   {
      concatText = ConcatStrings("Maksimum dla tego nauczyciela wynosi ",IntToString(teacherMAX));
      PrintScreen(concatText,-1,-1,"FONT_OLD_20_WHITE.TGA",2);
      B_Say(slf,oth,"$NOLEARNYOUREBETTER");
      return FALSE;
   };
   if((realAttribute + points) > teacherMAX)
   {
      concatText = ConcatStrings("Maksimum dla tego nauczyciela wynosi ",IntToString(teacherMAX));
      PrintScreen(concatText,-1,-1,"FONT_OLD_20_WHITE.TGA",2);
      B_Say(slf,oth,"$NOLEARNOVERPERSONALMAX");
      return FALSE;
   };
   if(oth.lp < kosten)
   {
      PrintScreen("Za mało Punktów Nauki!",-1,-1,"FONT_OLD_20_WHITE.TGA",2);
      B_Say(slf,oth,"$NOLEARNNOPOINTS");
      return FALSE;
   };
   oth.lp = oth.lp - kosten;
   B_RaiseAttribute_Gothic2(oth,attrib,points);
   return TRUE;
};

2. Musicie teraz przebudować nauczycielom pliki dialogowe tak by nauka odbywała się z systemu z Gothic 2. W przeciwnym razie w dalszym ciągu będą nauczać zgodnie z systemem z Gothic 1. Niżej podrzucam przykładowy przebudowany dialog ze Scattym jakby ktoś potrzebował szablonu do przekopiowania (broń jednoręczna i dwuręczna).

// **************************************************
// TRAIN 1H - NOTR
// **************************************************

instance Cord_Training_NotRCombat(C_Info)
{
npc = SLD_709_Cord;
condition = Cord_Training_NotRCombat_Condition;
information = Cord_Training_NotRCombat_Info;
important = 0;
permanent = 1;
description = "Naucz mnie walczyć bronią jednoręczną";
};


func int Cord_Training_NotRCombat_Condition()
{
if (Npc_KnowsInfo(hero,SLD_709_Cord_TRAINOFFER))
{
return 1;
};
};

func void Cord_Training_NotRCombat_Info()
{
Info_ClearChoices(Cord_Training_NotRCombat);
Info_AddChoice(Cord_Training_NotRCombat,"Wróć",Cord_Training_NotRCombat_BACK);

Info_AddChoice(Cord_Training_NotRCombat,B_BuildLearnString("Broń jednoręczna +1 za 50 bryłek rudy",B_GetLearnCostTalent(other,NPC_TALENT_1H,1),0),Cord_Training_NotRCombat_1H_1);
Info_AddChoice(Cord_Training_NotRCombat,B_BuildLearnString("Broń jednoręczna +5 za 250 bryłek rudy",B_GetLearnCostTalent(other,NPC_TALENT_1H,5),0),Cord_Training_NotRCombat_1H_5);

};

func void Cord_Training_NotRCombat_1H_1()
{
if (Npc_HasItems(other,itminugget) >= 50)
{
B_TeachFightTalentPercent(self,other,NPC_TALENT_1H,1,100);
B_GiveInvItems(other,self,itminugget,50);
Info_ClearChoices(Cord_Training_NotRCombat);
Info_AddChoice(Cord_Training_NotRCombat,Dialog_Back,Cord_Training_NotRCombat_Back);

Info_AddChoice(Cord_Training_NotRCombat,B_BuildLearnString("Broń jednoręczna +1 za 50 bryłek rudy",B_GetLearnCostTalent(other,NPC_TALENT_1H,1),0),Cord_Training_NotRCombat_1H_1);
Info_AddChoice(Cord_Training_NotRCombat,B_BuildLearnString("Broń jednoręczna +5 za 250 bryłek rudy",B_GetLearnCostTalent(other,NPC_TALENT_1H,5),0),Cord_Training_NotRCombat_1H_5);
}
else
{
AI_Output (self,other,"DIA_Cord_TRAIN_2h_NoOre_01_00"); //Wróć, gdy będziesz miał wystarczająco dużo rudy.
Info_ClearChoices(Cord_Training_NotRCombat);
};
};

func void Cord_Training_NotRCombat_1H_5()
{
if (Npc_HasItems(other,itminugget) >= 250)
{
B_TeachFightTalentPercent(self,other,NPC_TALENT_1H,5,100);
B_GiveInvItems(other,self,itminugget,250);
Info_ClearChoices(Cord_Training_NotRCombat);
Info_AddChoice(Cord_Training_NotRCombat,Dialog_Back,Cord_Training_NotRCombat_Back);

Info_AddChoice(Cord_Training_NotRCombat,B_BuildLearnString("Broń jednoręczna +1 za 50 bryłek rudy",B_GetLearnCostTalent(other,NPC_TALENT_1H,1),0),Cord_Training_NotRCombat_1H_1);
Info_AddChoice(Cord_Training_NotRCombat,B_BuildLearnString("Broń jednoręczna +5 za 250 bryłek rudy",B_GetLearnCostTalent(other,NPC_TALENT_1H,5),0),Cord_Training_NotRCombat_1H_5);

}
else
{
AI_Output (self,other,"DIA_Cord_TRAIN_2h_NoOre_01_00"); //Wróć, gdy będziesz miał wystarczająco dużo rudy.
};
};

func void Cord_Training_NotRCombat_BACK()
{
Info_ClearChoices(Cord_Training_NotRCombat);
};

// **************************************************
// TRAIN 2H - NOTR
// **************************************************

instance Cord_Training_NotRCombat2H(C_Info)
{
npc = SLD_709_Cord;
condition = Cord_Training_NotRCombat2H_Condition;
information = Cord_Training_NotRCombat2H_Info;
important = 0;
permanent = 1;
description = "Naucz mnie walczyć bronią dwuręczną";
};


func int Cord_Training_NotRCombat2H_Condition()
{
if (Npc_KnowsInfo(hero,SLD_709_Cord_TRAINOFFER))
{
return 1;
};
};

func void Cord_Training_NotRCombat2H_Info()
{
Info_ClearChoices(Cord_Training_NotRCombat2H);
Info_AddChoice(Cord_Training_NotRCombat2H,"Wróć",Cord_Training_NotRCombat2H_BACK);

Info_AddChoice(Cord_Training_NotRCombat2H,B_BuildLearnString("Broń dwuręczna +1 za 50 bryłek rudy",B_GetLearnCostTalent(other,NPC_TALENT_2H,1),0),Cord_Training_NotRCombat2H_2H_1);
Info_AddChoice(Cord_Training_NotRCombat2H,B_BuildLearnString("Broń dwuręczna +5 za 250 bryłek rudy",B_GetLearnCostTalent(other,NPC_TALENT_2H,5),0),Cord_Training_NotRCombat2H_2H_5);

};

func void Cord_Training_NotRCombat2H_2H_1()
{
if (Npc_HasItems(other,itminugget) >= 50)
{
B_TeachFightTalentPercent(self,other,NPC_TALENT_2H,1,100);
B_GiveInvItems(other,self,itminugget,50);
Info_ClearChoices(Cord_Training_NotRCombat2H);
Info_AddChoice(Cord_Training_NotRCombat2H,Dialog_Back,Cord_Training_NotRCombat2H_Back);

Info_AddChoice(Cord_Training_NotRCombat2H,B_BuildLearnString("Broń dwuręczna +1 za 50 bryłek rudy",B_GetLearnCostTalent(other,NPC_TALENT_2H,1),0),Cord_Training_NotRCombat2H_2H_1);
Info_AddChoice(Cord_Training_NotRCombat2H,B_BuildLearnString("Broń dwuręczna +5 za 250 bryłek rudy",B_GetLearnCostTalent(other,NPC_TALENT_2H,5),0),Cord_Training_NotRCombat2H_2H_5);
}
else
{
AI_Output (self,other,"DIA_Cord_TRAIN_2h_NoOre_01_00"); //Wróć, gdy będziesz miał wystarczająco dużo rudy.
Info_ClearChoices(Cord_Training_NotRCombat2H);
};
};

func void Cord_Training_NotRCombat2H_2H_5()
{
if (Npc_HasItems(other,itminugget) >= 250)
{
B_TeachFightTalentPercent(self,other,NPC_TALENT_2H,5,100);
B_GiveInvItems(other,self,itminugget,250);
Info_ClearChoices(Cord_Training_NotRCombat2H);
Info_AddChoice(Cord_Training_NotRCombat2H,Dialog_Back,Cord_Training_NotRCombat2H_Back);

Info_AddChoice(Cord_Training_NotRCombat2H,B_BuildLearnString("Broń dwuręczna +1 za 50 bryłek rudy",B_GetLearnCostTalent(other,NPC_TALENT_2H,1),0),Cord_Training_NotRCombat2H_2H_1);
Info_AddChoice(Cord_Training_NotRCombat2H,B_BuildLearnString("Broń dwuręczna +5 za 250 bryłek rudy",B_GetLearnCostTalent(other,NPC_TALENT_2H,5),0),Cord_Training_NotRCombat2H_2H_5);

}
else
{
AI_Output (self,other,"DIA_Cord_TRAIN_2h_NoOre_01_00"); //Wróć, gdy będziesz miał wystarczająco dużo rudy.
};
};

func void Cord_Training_NotRCombat2H_BACK()
{
Info_ClearChoices(Cord_Training_NotRCombat2H);
};

3. Warto też pamiętać o tej podmiance w pliku "Gothic\_work\DATA\scripts\Content\Story\text.d" (zielony, wojownik, mistrz).

4. Odnośnie umiejętności bojowych możesz też wstawić w pliku "pc_hero.d" linijkę "Npc_SetTalentValue(self, NPC_TALENT_1H,10);" bo w Gothic 2 postać zaczyna z 10% umiejętności, a w Gothic 1 z 0%.

Jakby ktoś nie pamiętał wszystkich nauczycieli to polecam Gothicpedię :)
https://gothic.fandom.com/pl/wiki/Nauczyciele_w_Gothic

PS: Żeby nie było - sposób w jaki dodać ten system do gry opracował @bgb. Ja wrzucam tylko drobne uzupełnienie w postaci gotowca do wklejenia dla leniwych bo sam miałem pewien problem z implementacją tego do gry.

Strony: [1] 2 3
Do góry