by Zed Nocear

 

I. Wykorzystanie pozycji skryptów CRE


Wszyscy "aktorzy" występujący w grze, a więc postać głównego bohatera, postacie przyłączalne do drużyny (tzw. NPC-e), oraz postacie neutralne, wrogowie, zwierzęta i potwory (tzw. BN-i), a nawet nieinteraktywne przelatujące na mapach ptaki i manekiny treningowe w wieży Durlaga są definiowane w grze jako pliki CRE. Bez przypisanym im skryptom i dialogom, których nazwy plików znajdują się w pliku CRE "aktorzy" nie ruszaliby się i nie reagowali na otoczenie. Staliby jak kołki i nic więcej (To częsty problem początkujących moderów: "Stworzyłem postać, ale ona w ogóle nie rusza się/ nie walczy, dlaczego?")

 

Jest 5 poziomów skryptu postaci/potwora odpowiadających 5-u miejscom na przypisanie nazwy skryptu w pliku CRE. Zawartość istniejących skryptów dodawana jest do kolejki bloków według poniższej kolejności. Skrypty sprawdzane są w tej kolejności, jeśli żaden warunek w skrypcie nie jest prawdziwy, program przechodzi do następnego skryptu i tak aż do końca. Jeśli któryś z bloków skryptu ma spełniony warunek, zostanie wykonany, a cała kolejka rozpoczyna się od początku (pierwszego bloku pierwszego istniejącego skryptu). Wyjątek stanowi instrukcja Continue() w bloku, powodująca, że po wykonaniu instrukcji tego bloku, nie następuje restart kolejki, lecz sprawdzanie bloków jest kontynuowane, według kolejności dalej:

1. Override

2. Class

3. Race

4. General

5. Default

 

Uwaga! Instrukcja Continue() zawiera pewną pułapkę dla niedoświadczonego moddera: wartości zmiennych zmieniane instrukcjami w blokach są aktualizowane dopiero przy restarcie kolejki, dlatego nie można zmienić wartości zmiennej w jednym bloku, wymusić instrukcją Continue() kontynuowanie sprawdzania dalszych bloków skryptów i w jednym z nich wykorzystać zmienioną wartość zmiennej, bo nadal będzie odczytywana jej stara wartość. Może to być źródłem błędu trudnego do namierzenia.

 

Nie ma ścisłych reguł, co do tego, które skrypty należy umieszczać na której pozycji. W oryginalnych plikach BG1 widać pewne tendencje, ale tyle jest wyjątków, nawet wśród NPC-ów, że ogólnie panuje całkowity bałagan.

 

Wyłączenie AI członków drużyny powoduje wyłączenie wszystkich skryptów postaci drużyny z wyjątkiem skryptu Override.

 

BG1 jest ubogi w skrypty globalne działające przez cały czas gry. Nie funkcjonuje BALDUR.BCS, ani BALDUR25.BCS (ToB), nie ma PLAYER1D.BCS uruchamianego przy odpoczynku drużyny (rest). Działają tylko DPLAYER3.BCS u głównego bohatera (w multi u wszystkich postaci graczy) i DPLAYER2.BCS na przyłączonych członkach drużyny. Przy czym tylko DPLAYER3.BCS na pozycji Override głównej postaci nie zostaje wyłączony przy inaktywacji AI drużyny, więc mamy pewność, że będzie działał przez cały czas gry, niezależnie od poczynań gracza.

 

1. Override script

· zazwyczaj skrypt najbardziej specyficzny dla danego CRE.

· większość NPC-ów ma swój osobisty skrypt, niektóre nie mają takich w ogóle (tylko skrypty ogólne, dzielone z innymi CRE), Alora ma swój skrypt osobisty w slocie Race, czyli przestaje działać przy wyłączeniu AI (błąd?).

· Postać główna i postacie w multi mają tu przypisany DPLAYER3.BCS.

2. Class script

· BN-i i nieprzyłączeni NPC-e – zazwyczaj skrypt do walki specyficzny dla klasy (mag, kapłan, złodziej) lub nic.

· u członków drużyny zapisany tu skrypt jest maskowany przez skrypt BS (skrypt AI walki z podkatalogu Scripts gry) wybierany z panelu cech postaci. Maskowanie działa stale. Nawet jeśli jest ustawiony skrypt w CRE, a my nie wybierzemy skryptu AI (ustawienie none/żaden), to nie będzie działał skrypt zapisany w CRE tylko żaden.

3. Race script

· zazwyczaj nic (pusty), Alora ma tu ustawiony skrypt osobisty.

4. General script

· zazwyczaj prosty skrypt walki wręcz lub dystansowej (najczęściej WTASIGHT, WTARSGT), albo nic.

5. Default script

· BN-i różnie, czasami j/w.

· Postać główna i postacie w multi mają tu przypisany DPLAYER3.BCS (tak samo jak na pozycji Override).

· przyłączalni NPC-e mają ustawiony DPLAYER.BCS, po włączeniu do drużyny jest zmieniany na DPLAYER2.BCS, a przy odłączaniu zmieniany na odwrót. Zamiana skryptów odbywa się za każdym razem, także jeśli wielokrotnie przyłączamy i odłączamy tego samego NPCa.

 

II. Rozważania na temat dialogów


1. W BG1 w przeciwieństwie do BG2 i PT przy najechaniu kursorem rozmowy na postać z drużyny, kursor pozostaje nieaktywny (przyciemniony). Nie można więc w ten prosty sposób porozmawiać z członkami drużyny, jak jest to fantastycznie rozwinięte w PT. W BG2 w wersji oryginalnej takich dialogów nie ma, ale możliwość wykorzystują niektóre mody np. NPC Flirt Pack. Nie znaczy to, że w BG1 nie można wymusić dialogu z członkiem drużyny, ale trzeba użyć nieco mniej naturalnych/intuicyjnych metod, np. poprzez użycie klawiszy skrótów.

2. Przy tworzeniu nieco bardziej skomplikowanych dialogów do BG1 napotkałem na kilka nieoczekiwanych problemów:

a. wartość zmiennej modyfikowana poleceniem IncrementGlobal jest aktualizowana z opóźnieniem od drugiego bloku, tzn. warunki w następnym bloku dialogu odczytują jeszcze starą wartość, dopiero od drugiego bloku po bloku z instrukcją IncrementGlobal odczytywana jest zmieniona wartość. Natomiast polecenie SetGlobal działa natychmiast.

b. warunek Alignment(LastTalkedToBy,XXXX) w warunkach odpowiedzi (response triggers) nie rozpoznaje charakteru rozmówcy z naszej drużyny, nie mam pojęcia dlaczego.

 

UAKTUALNIENIE (2008-10-19): Jastey z Rosenranken.DE odkryła, że warunek Alingment działa jednak w dialogach w ograniczonym zakresie, przy spełnieniu dwóch kryteriów:

· zamiast tekstowych etykiet charakterów jak LAWFUL_GOOD należy stosować bezpośrednio ich numery z ALIGNMEN.IDS po przeliczeniu na system dziesiętny, czyli nie Alignment(LastTalkedToBy,CHAOTIC_EVIL) ale Alignment(LastTalkedToBy,51).

0x00 NONE

0x11 LAWFUL_GOOD

0x12 LAWFUL_NEUTRAL

0x13 LAWFUL_EVIL

0x21 NEUTRAL_GOOD

0x22 NEUTRAL

0x23 NEUTRAL_EVIL

0x31 CHAOTIC_GOOD

0x32 CHAOTIC_NEUTRAL

0x33 CHAOTIC_EVIL

· etykiety oznaczające grupy charakterów np. MASK_GOOD, czyli dowolny dobry charakter, nie działają w BG1 w ogóle, także w formie numerów.

0x01 MASK_GOOD

0x02 MASK_GENEUTRAL

0x03 MASK_EVIL

0x10 MASK_LAWFUL

0x20 MASK_LCNEUTRAL

0x30 MASK_CHAOTIC


UAKTUALNIENIE 2 (2008-12-16): Odkryłem, że można w łatwy sposób sprawić, aby etykiety tekstowe charakterów działały w BG1. Po prostu plik ALIGN.IDS z BG1, wykorzystywany w większości edytorów i kompilatorów IE, zawiera niewłaściwe numery dla części charakterów. Plik ALIGNMEN.IDS i ALIGN.IDS mają identyczną zawartość w BG2 i taką samą jak ALIGNMEN.IDS w BG1.Wystarczy skopiować ALIGNMEN.IDS jako plik ALIGN.IDS do folderu Override w BG1 i etykiety konkretnych charakterów działają. Maski nie działają dalej, ale to już wina enginu BG1.


Moja pierwotna interpretacja zachowania warunku Alignment była błędna. Rzeczywiście, przy użyciu etykiet tekstowych charakterów, warunek raz działa, a raz nie. Ale nie chodzi o to, że działa w warunkach bloku a nie działa w warunkach odpowiedzi (transitions), tylko, że działa dla jednych charakterów, a dla innych nie. Których? Wystarczy porównać numery w ALIGNMEN.IDS i ALIGN.IDS w BG1, tam gdzie się różnią, etykieta tekstowa nie działa. To samo dotyczy wszystkich innych ustawień charakteru w instrukcjach skryptowych i efektach czarów i przedmiotów, np. w plikach EFF.

 

III. Modowanie - namierzanie celów w skryptach w BG I


Próbowałem stworzyć skazę charakteru Kagaina w postaci lubowania się w mordowaniu wiewiórek. Jak jednak Kagain ma "zobaczyć" wiewiórkę, która nie ma ustawionego script name, a identyfikatory ANIMAL, NO_RACE i NO_CLASS dzieli z pozostałymi nieszkodliwymi zwierzątkami jak koty, kurczaki, nietoperze, ptaki, krowy i inne?

· Dodanie script name ~Squirrel~ do plików CRE wiewiórek i celowanie warunkiem See("Squirrel") nie sprawdziło się. Kagain zabijał pierwszą wiewiórkę i często potem już nie reagował na pozostałe. Wynika z tego, że script name jako wyznacznik obiektu jest dobry w skryptach tylko dla stworzeń unikalnych, w jednym egzemplarzu.

· W drugim podejściu dodałem do RACE.IDS nową rasę, dopisując wiersz ~160 SQUIRREL~ i odpowiednio zmieniając w plikach CRE wiewiórek NO_RACE na SQUIRREL. Teraz można było "polować" na wiewiórki warunkiem See([0.0.SQUIRREL]), Kagain reaguje przy takim warunku na wszystkie napotkane wiewiórki. Mimo to script name przydaje się, jeśli chcemy poznać ile ubiliśmy jakich stworzeń, bo właśnie na podstawie script name engine gry klasyfikuje ubite stwory przypisując odpowiednie wartości zmiennym o nazwie złożonej z tekstu SPRITE_IS_DEAD + treści script name, a te które nie mają ustawionego script name lądują do "wora" SPRITE_IS_DEADNONE.

 

IV. Modowanie – uruchamianie skryptu z przedmiotu w BG I


Jak wiadomo nie wszystkie rozwiązania w grze da się uzyskać przez efekty magiczne przedmiotu. Czasami konieczne jest posłużenie się skryptem, np. otwarcie sklepu z przedmiotu symulujące torby przechowywania w BG1 lub zasymulowanie gadającego przedmiotu w BG1

 

W grach IE nie ma bezpośrednio możliwości uruchomienia skryptu z przedmiotu. Standardowa technika moderska w BG2 polega na przywołaniu niewidocznego potwora z własności przedmiotu, który dalej załatwia sprawę. Jednakże w BG1 nie ma możliwości stworzenia prawdziwie niewidocznego potwora, a jeśli będzie on nawet prawie niewidoczny (np. animacja ptaka lub nietoperza z całkowitą przeźroczystością) to pozostaje animacja dymu towarzyszącego efektowi Summon Creature, której nijak nie da się wyłączyć.

 

Można to obejść przywołując potwora ze skryptu Dplayer3, który jest jedynym działającym w BG1 skryptem przez cały czas gry. Technika jest następująca:

1. W przedmiocie ustawiamy efekt magiczny Store Local Variable [187] z celem "Party". Przy okazji ustawienie zmiennej typu "LOCALS" działa także bezpośrednio z przedmiotu, a nie jak jest podane w bazie IESDP, że tylko w plikach EFF.

2. W dplayer3.bcs dodajemy jeden blok, który wyłapuje zmianę wartości zmiennej i przywołuje potwora, czemu nie towarzyszą żadne dodatkowe efekty graficzno-dźwiękowe.

3. Skrypt ustawiony na potworze załatwia już nam resztę, co chcemy, czyli np. otwiera sklep dla osoby, która posiada "torbę przechowywania".

 

Przykład z TWM rozwiązania torby przechowywania w BG1 (blok w Dplayer3.BCS):

 

IF
Global("bag01use","LOCALS",1)
THEN
RESPONSE #100
SetGlobal("bag01use","LOCALS",0)
CreateCreature("Z!BAG01",[0.0],1)
END

 

V. Niezgodność poleceń skryptowych i efektów magicznych ze specyfikacją w BG I


Polecenie 141 GivePartyGoldGlobal(S:Name*,S:Area*) nie działa zgodnie z założeniami w BG1. Zamiast dawać drużynie ilość złota odpowiadającą wartości zmiennej, daje ilość złota odpowiadającą wartości parametru "gold" pliku CRE, a wartość zmiennej ignoruje.

Efekt Create Inventory Item [122] został zaimplementowany w BG1 częściowo: tworzony jest jeden przedmiot a parametr ilości musi być ustawiony na "0", ponadto przedmiot tworzony jest tylko w trybie Delay/Permanent, przy Instant/Permanent nic się nie dzieje.

Polecenia 116 TakePartyItem(S:Item*) i 204 TakePartyItemNum(S:ResRef*,I:Num*) nie uwzględniają liczby przedmiotów w stosie, tylko cały stos traktują jako jeden przedmiot. To powoduje, że w przypadku grupowalnych przedmiotów gra zabiera wszystkie a nie odpowiednio jeden lub wyznaczoną ilość, jeśli są one zebrane do jednej przegródki inwentarza.

Polecenie 13 FindTraps() nie działa w skrypcie AI, wręcz uniemożliwia wykorzystanie tej funkcji z klawisza interfejsu, wyłączając ją nieustannie. A wielka szkoda, bo złodziej automatycznie poszukujący pułapek, gdy nie ma nic innego do roboty byłby wielkim ułatwieniem w BG1.

Efekt Cast Spell (at Creature) [146] i Cast Spell (at Point) [148] nie działają z wnętrza pliku EFF. Ponadto ustawienie parametru 'Casting Level' na "0" nie powoduje rzucenia czaru na poziomie stworzenia CRE jak w BG2, tylko jest rzucany na poziomie 1. Nie można więc w BG1 stworzyć przedmiotów zawierających czar rzucany z mocą zależną od poziomu postaci używającej przedmiot. Poziom rzucania musi być ustawiony "na sztywno".

 

VI. Ograniczenia użycia rodzajów zmiennych w BG I


W BG1, podobnie jak w innych grach IE, funkcjonują trzy rodzaje zmiennych:

· typu "GLOBAL", których wartość dostępna jest z każdego skryptu (dialogu) w grze, zapisywane w Save'ie w Baldur.GAM.

· typu "LOCALS", których wartość dostępna jest tylko dla postaci (CRE), w której skrypcie (dialogu) została utworzona. W ten sposób zmienna typu "LOCALS" o tej samej nazwie może przyjmować odrębne wartości dla poszczególnych CRE a jeden uniwersalny skrypt może dawać różne efekty działania dla poszczególnych postaci. W BG2 zmienna zapisywana jest jako efekt w pliku CRE, będącym częścią Baldur.GAM (postacie przyłączalne do drużyny) lub Baldur.SAV (pozostałe CRE)

· typu "AREA", których wartość dostępna jest tylko w obrębie określonej lokacji (ARE). W ten sposób zmienna typu "AREA" o tej samej nazwie może przyjmować odrębne wartości dla poszczególnych lokacji a jeden uniwersalny skrypt może dawać różne efekty działania w zależności od lokacji na której jest on aktywny. Zmienne typu "AREA" zapisywane są w Save'ie w odpowiednich plikach ARE odwiedzonych obszarów jako część pliku Baldur.SAV

 

W niezmodowanym BG1 praktycznie 100% zmiennych jest typu "GLOBAL", tylko w dwóch miejscach z dodatku TotSC wykorzystane zostały zmienne typu "AREA". Nie ma zmiennych typu "LOCALS".

UAKTUALNIENIE (2011-06-02): Faktycznie zmienne typu "GLOBAL" można by używać niemal w każdej sytuacji (i taka jest praktyka w większości modów do BG1), gdyby nie jeden istotny szkopuł: engine BG1 obsługuje maksymalnie 1024 zmiennych globalnych. Zmienne dodawane są do listy przy pierwszym ustawieniu ich wartości w trakcie rozgrywki. Do limitu wlicza się także timery i "ScriptName" zabitych stworzeń, gdyż gra automatycznie tworzy zmienną "SPRITE_IS_DEADScriptName". Po osiągnięciu limitu nadal można zmieniać wartości wcześniej użytych zmiennych, ale ustawienia wartości nowych zmiennych są ignorowane i gra się sypie (przestają zaskakiwać zdarzenia zależne od wartości nowych zmiennych). Problem jest poważny, bo limit łatwiej osiągnąć, niż się zdaje. Z własnego doświadczenia grając w konfiguracji BG1-TotSC+TGCe1+BGQE+TWMv3 i przechodząc wszystkie możliwe questy poboczne, gra zacięła mi się w 7. rozdziale w trakcie uroczystości w Pałacu Książęcym. A nie jest to specjalnie przeładowana modami konfiguracja. Dlatego w ramach praktyki poprawnego modowania BG1 warto ograniczyć użycie zmiennych globalnych do niezbędnego minimum.

 

Zmienne typu "LOCALS" działają w BG1 zupełnie prawidłowo, ale nie są zapisywane w Save'ie, mogą więc być wykorzystane tylko jako krótkotrwałe zmienne pomocnicze, gdzie nie przeszkadza ich każdorazowe wyzerowanie wartości przy kolejnym załadowaniu gry. Może to potraktować nawet jako zaletę, gdyż nie obciążają dodatkowo zapisu stanu gry i limitu liczby zmiennych globalnych.

 

Zmienne typu "AREA" są w BG1 ułomną wersję zmiennych typu "GLOBAL", bo nie działa parametr "MYAREA", oznaczający domyślnie aktualną lokację. Konieczne jest więc w odwołaniu do zmiennej podawanie konkretnej nazwy lokacji, np. "AR0125". Z dostępnością zmiennej tylko na wybranej planszy też nie jest do końca tak, jak by można przypuszczać. Kiedy na próbę rozproszyłem drużynę we Wrotach Baldura po różnych lokacjach (wnętrzach budynku), to zmienna typu "AREA" stworzona w skrypcie postaci na jednej lokacji dawała się odczytać przez postacie na innych lokacjach. Nie wiem, czy to reguła, czy tak jest tylko w BG1. Choć gdyby w odwołaniu do zmiennej można było użyć parametru MYAREA, ten problem by nie zaistniał. Jedynym, ale bardzo poważnym uzasadnieniem używania zmiennych typu "AREA" jest limit maksymalnie 1024 jednocześnie stosowanych zmiennych globalnych w grze i konieczność ich oszczędzania. Warto używać zmiennych typu "AREA" wszędzie, gdzie tylko jest to możliwe, czyli użycie zmiennej ograniczone jest do jednej lokacji (typowy przykład to jednorazowe przywołanie NPCa skryptem lokacji).

 

Zasady poprawnego modowania BG1, ograniczające wykorzystanie zmiennych globalnych:

· Stosuj zmienne typu "AREA" lub "LOCALS", gdzie tylko jest to możliwe;

· W wieloetapowych questach używaj kolejnych wartości jednej zmiennej globalnej, zamiast osobnych zmiennych dla każdego zdarzenia; stosuj "recycling" zmiennych globalnych, gdzie tylko to możliwe;

· Nie nadawaj unikalnych "ScriptName" przeciwnikom do zabicia, jeśli nie zamierzasz w skrypcie/dialogu odwoływać się do nich przez ich "ScriptName".

 

VII. Znaczenie niektórych offsetów spawn pointów w plikach ARE


Baza IESDP podaje, że w 200-bajtowym bloku charakteryzującym każdy spawn point w pliku ARE offset 0x7a umożliwia zmianę trybu działania: wartość 2 (tryb "revealed") oznacza przywołanie potworów za każdym wejściem spawn pointu w pole widzenia drużyny, wartość 1 (tryb "rest') oznacza, że spawn point zadziała tylko raz po każdym odpoczynku (a także po pierwszym wejściu na lokację i po każdym załadowaniu gry).

 

Wszystkie spawn pointy w BG1 działają w trybie "revealed", co w przypadku niektórych lokacji (ruiny Firewine, wioska Xwartów, poziom koszar w Kopalni Kniei Otulisko) powoduje nieskończone utarczki z ciągle powstającymi grupami słabych potworów. Postanowiłem stworzyć mod, który zmieniałby tryb działania wszystkich spawn pointów w grze na "rest". Niestety pierwsze próby zakończyły się niepowodzeniem. Po dłuższych testach okazało się, że offset zmieniający tryb pracy spawn pointów znajduje się pod adresem 0x76. Baza IESDP podaje jego znaczenie jako " Base creature number to spawn", podobnie NEAR Infinity: "Spawn frequency?". Przy bliższym przyjrzeniu interpretacja offsetów z IESDP i NI różnią się, i według moich doświadczeń obie nie są do końca prawidłowe. Tak wygląda kod w TP2 WeiDU zmieniający tryb działania wszystkich spawn pointów w grze w moim modzie TWM:

 

COPY_EXISTING_REGEXP GLOB ~.*\.ARE~ ~override~
READ_LONG "0x64" "#spawn"
READ_LONG "0x60" "spawn_off"
WHILE ("%#spawn%" > 0) BEGIN
SET "#spawn" = ("%#spawn%" - 1)
WRITE_SHORT ("%spawn_off%" + 0x76) 1 // Spawn method = Rest
SET "spawn_off" = ("%spawn_off%" + 200)
END
BUT_ONLY_IF_IT_CHANGES

 

VIII. Dziwactwa systemu losowych przedmiotów w BG I


W BG1 występują 4 pliki 2DA: RNDEQUIP.2DA, RNDSCROL.2DA, RNDMAGIC.2DA i RNDTREAS.2DA. Struktura tych plików, na przykładzie RNDTREAS.2DA, jest następująca (niestety, nie jest ona prawidłowo wyswietlana przez przeglądarkę IE 6):

2DA V1.0
*
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
POOR MISC19 004 002 001 RNDSCR01 001 001 * * * 001 001 001 001 002 002 003 003 MISC16
AVERAGE RNDMAG01 MISC23 AMUL05 MISC17 015 012 010 008 006 003 * 001 007 009 RNDSCR01 MISC18 MISC22 AMUL06 RING12
WELL_OFF RNDMAG01 MISC31 AMUL08 MISC20 034 AMUL09 RNDSCR01 008 009 RING11 023 RNDSCR01 RING14 MISC26 MISC25 057 MISC27 MISC28 AMUL04
WEALTHY RNDMAG01 RING18 MISC37 MISC35 RING16 AMUL07 RNDSCR02 047 038 029 AMUL09 RING10 RING15 RNDSCR02 RING13 RING17 MISC34 MISC36 RNDMAG02
RICH RNDMAG02 RNDMAG01 MISC43 AMUL11 AMUL12 AMUL13 AMUL10 MISC29 MISC21 073 MISC24 RNDSCR03 MISC34 MISC38 RNDSCR03 MISC40 MISC42 RNDMAG01 RNDMAG02

 

Pierwsze trzy wiersze pliku stanowią nagłówek. Kolejne wiersze definiują losowe przedmioty. Pierwsza kolumna w każdym wierszu zawiera opis jego zawartości i może być dowolny, nie jest wykorzystywany przez grę. Następne 19 kolumn zawiera pulę nazw przedmiotów ITM do losowania, do której można się odwoływać przez nazwę losowego pseudoprzedmiotu na którą składa się 6 pierwszych liter nazwy pliku 2DA i dwie litery identyfikatora wiersza. Czyli dla przykładowego RNDTREAS.2DA do wiersza "poor" odwołujemy się przez RNDTRE01.ITM, "average" to RNDTRE02.ITM itd.

 

W miejscu nazw przedmiotów do losowania zamiast nazwy realnego przedmiotu z zasobów gry można wpisać:

· gwiazdkę "*" – oznacza, że w grze ostatecznie nie pojawi się żaden przedmiot, jeśli zostanie wylosowana ta pozycja

· trzycyfrową liczbę – jako losowy skarb pojawi się wyznaczona liczba sztuk złota

· nazwę losowego pseudoprzedmiotu np. RNDMAG01 odnosi się do pierwszej puli przedmiotów z RNDMAGIC.2DA. RNDTREAS.2DA może odwoływać się do RNDMAGIC.2DA i RNDSCROL.2DA a RNDMAGIC.2DA tylko do RNDSCROL.2DA. System nie jest elastyczny i inne odwołania między plikami 2DA nie działają.

 

Ponadto w zasobach przedmiotów gry figuruje pięć pseudoprzedmiotów, stanowiących pusty szablon struktury pliku ITM: RNDTRE01.ITM, RNDTRE02.ITM, RNDTRE03.ITM, RNDTRE04.ITM i RNDTRE05.ITM. Właściwości tych pseudoprzedmiotów są nieistotne ponieważ gra natychmiast po wczytaniu pliku planszy/stworzenia podmienia je na właściwy przedmiot wybrany losowo z puli przedmiotów zapisanych w wierszu pliku 2DA, który to wiersz odpowiada nazwie pseudoprzedmiotu.

 

System ten jest w oryginalnej grze BG1 wykorzystywany w niewielkim stopniu, tylko do tworzenia losowych skarbów w inwentarzu przeciwników. Tymczasem działa także pojemnikach plansz oraz przy przywoływaniu przedmiotów instrukcjami skryptowymi np. CreateItem("RNDTRE01",1,0,0). Do zadziałania stworzenia losowego przedmiotu w inwentarzu stworzeń i pojemnikach plansz wystarczy sam wpis w odpowiednim pliku 2DA, do stworzenia losowego przedmiotu instrukcją skryptową niezbędne jest istnienie pseudoprzedmiotu o podawanej nazwie fizycznie w zasobach gry, który następnie gra dopiero podmienia losowo na jeden z przedmiotów z ustalonej puli (w naszym przykładzie RNDTRE01.ITM). System podmiany nazwy pseudoprzedmiotu na losowy przedmiot z puli zapisanej w pliku 2DA nie działa niestety w plikach sklepów, czyli nie da się stworzyć coś na kształt hazardu z Diablo2, gdzie kupujemy w ciemno niezidentyfikowany przedmiot, który może okazać się zazwyczaj tanim badziewiem, a sporadycznie potężnym artefaktem.

 

Oryginalna gra BG1+TotSC nie wykorzystuje pliku RNDEQUIP.2DA, który jest kopią RNDMAGIC.2DA. Nie znam też modów, które by używały ten plik. Dlatego zaanektowałem go na potrzeby moda TWM. Powstaje pytanie, jak pojemny jest losowy system BG1, czyli ile wierszy i ile wpisów w każdym wierszu jest w stanie obsłużyć engine BG1? Mod NTotSC rozbudowuje plik RNDSCROL.2DA zarówno dodając nowy wiersz, jak i dodając dodatkowe wpisy w wierszu.

 

UAKTUALNIENIE (2008-10-19): Sprawdziłem i niestety w plikach RNDxxxxx.2DA dodawane kolumny o numerach powyżej 20. są ignorowane przez engine BG1, a pula przedmiotów w wierszu może liczyć maksymalnie 19 pozycji (czyli też zwoje wpisane na pozycjach powyżej numeru 20. w RNDSCROL.2DA w NTotSC 2.1 nie będą pojawiać się w trakcie rozgrywki, choć gra nie protestuje, że struktura pliku jest błędna).

 

Natomiast elementem limitującym ilość działających wierszy w pliku RNDxxxxx.2DA a więc i maksymalną liczbę dostępnych pul przedmiotów do losowania jest liczba nazw pseudoprzedmiotu rozpoznawana przez engine gry i podmieniana losowo na jeden z przedmiotów wpisanych w wierszu. Oryginalne BG1 wykorzystuje maksymalnie 5 wierszy w RNDSCROL.2DA, NTotSC 6 wierszy. Biorąc na tapetę niewykorzystywane RNDEQUIP.2DA pierwszym 9. wierszom odpowiada RNDEQU01 do RNDEQU09. Mimo odpowiedniego wypełnienia dalszych wierszy w RNDEQUIP.2DA nazwa RNDEQU10 nie generuje żadnego przedmiotu a dla nazw RNDEQU11- RNDEQU19 losowane są przedmioty z wierszy odpowiadających RNDEQU01 do RNDEQU09. Widać więc, że gra nie bierze pod uwagę cyfry na 7. pozycji nazwy pseudoprzedmiotu. Czyżby więc dziewięć działających wierszy to maksimum, co można uzyskać? Biorąc pod uwagę już wykorzystane przez grę wiersze w plikach RNDxxxxx.2DA, zostałoby bardzo mało pozycji na nowe pule losowych przedmiotów dla modów. I tu czekała na mnie największa niespodzianka funkcjonowania plików RNDxxxxx.2DA. Engine gry rozpoznaje także litery alfabetu, co daje dodatkowe 26 nazw od RNDEQU0a do RNDEQU0z, przypisując im wiersze w RNDEQUIP.2DA od 17 w górę. Jakie nazwy odpowiadają wierszom od 10. do 16. i czy w ogóle istnieją, nie mam pojęcia. Wykorzystanie jednak tego odkrycia daje ogromne możliwości we wprowadzaniu losowości przedmiotów do świata BG1. W grze BG2 występuje dodatkowo plik RNDWEP.2DA, ale mam nadzieję, że poza tym cały system działa identycznie.

 


 

Podziękowania, opinie i komentarze
(wybierz księga gości w menu na górze)