sobota, 5 grudnia 2009

RepackGenerator

scr Poprzednio wspominałem o prostym projekciku generującym repacki z podanej puli kart Magic: the Gathering. Jest to pewne ułatwienie w przypadku organizacji jakiegoś common draftu bądź innych wydarzeń. Nie sądzę jednak, żeby to dalej rozwijać lub komuś to wciskać – ważniejsza tutaj jest chyba wartość programistyczna.

Naszym niedawnym projektem na przedmiot Programowanie Obiektowe było przygotowanie programu, którzy zarządzałby obiektami w strukturze klas podobnej do drzewa. Oczywiście, chodziło o zaznajomienie studenta z dziedziczeniem, polimorfizmem i innych aspektami OOP-u, ale samo zadanie było dosyć ciekawe. Ponieważ nie napisałem go (jako projekt oddałem framework – Yestę), postanowiłem nadrobić zaległości w wykorzystywaniu obiektowości i powstał RepackGenerator.

Idea kodu jest oczywista (jak się na niego spojrzy) – jeden obiekt zarządzający wszystkim, co się dzieje w programie, a interfejs ogranicza się do konsoli ze znakiem zachęty. Bardzo mi się podoba ta idea – może dlatego, że Bash to jest jedna z kilku rzeczy, jakie mi się podobają w systemach uniksowych.

Ten projekt był też okazją, aby zapoznać się z systemem dokumentowania Doxygen. Wyszło całkiem sympatycznie – wygląda estetycznie i politycznie poprawnie. Jedyną wadą tego rozwiązania jest niewygodny sposób komentowania kodu, ale z drugiej strony nie widzę innego sposobu na mechanizm dokumentowania źródeł. Cóż – i tak muszę się z tym zaprzyjaźnić w kontekście uczelni. A poza tym – wypadałoby.

Jak widać, na screenie, nie wpisałem ambitnych kart do testowania. Właściwie, to w ogóle kart nie wpisałem – przyznaję, iż nie chciało mi się wtłaczać mojej bazy tzw. “crapów” (niewiele wartych kart, które można wykorzystać do takich zabaw). Ważniejszy na chwilę obecną był jednak aspekt informatyczny i edukacyjny programu.

Linki, pod którymi możecie znaleźć program wraz z źródłami i dokumentacją:

Czekam na komentarze i uwagi. Mam również pewną przykrą informację – na razie zarzucam framework i prawdopodobnie nie będę już w nim implementował generowania terenu. Dobra wiadomość jest jednak taka, że jak znajdę trochę czasu, rozpocznę w końcu prace nad silnikiem – wiem, że powtarzam to jak mantrę od paru miesięcy, ale właśnie ten teren (oprócz studiów) najbardziej mnie hamował pod tym względem. Pozostaje jeszcze przezwyciężyć lenistwo.

Pozdrawiam i dziękuję – SceNtriC.

Ajajaj – aż trzy tygodnie

Znowu przerwa… Dobra informacja jest jednak taka, że powoli kończy się “gorący okres” (zwany też “puść ziemniaka”) na Politechnice. Oddanie systemu eksperckiego, kolokwium z Programowania Obiektowego (o ekstremalnym poziomie trudności), wejściówki wszelakie (a raczej groźba ich wystąpienia) – to tematy, którymi zajmowałem się ostatnio. Na szczęście, w najbliższym czasie czeka mnie tylko oddanie pierwszego rozwiązania na Optymalizację Kombinatoryczną (z zagadnienia, które niedawno opisywałemJob Shop). A na co przychodzi pora, jak na uczelni nieco się rozluźnia? Na denerwowanie wszystkich opowieściami o Wielkim Mistrzu.

Nie odkryję Ameryki (Wschodnio-Południowej), gdy rzeknę, iż w chwili obecnej trwa dostrajanie pewnych rzeczy i myślenie o małej promocji gry. Jesteśmy też zajęci szukaniem niektórych grafik. Ale najważniejszą zmianą jest bez wątpienia to, co pewnie tutaj widać na screenach (jeżeli jeszcze sobie nie poszły na obiad) – mapowanie wypukłości. Bump mapping, relief mapping, jak-miło mapping – sporo osób chciało, żeby to zaimplementować. Na razie są jeszcze jednak małe problemy na niektórych konfiguracjach i niestety, jeżeli nic się pod tym względem nie zmieni, to trzeba będzie z tego zrezygnować w finalnej wersji. Tym niemniej, na pozostałych konfiguracjach działa i widać, jak to wygląda – wreszcie czuć klimat lochów. Chwała naszym programistom (Toxic, Krajek, Voytech i bodajże Dab się włączył – pozdrawiam). Wracając jeszcze do screenów - na tej stronie mogą być zbyt małe, natomiast tutaj znajdziecie normalne wersje.

Niedawno (właściwie to przed godziną) skończyłem mój kilkugodzinny projekcik, który miał dwojakie znaczenie. Po pierwsze, ułatwiałby tworzenie “repacków” z puli kart Magic: the Gathering – są to 15-kartowe paczki o zawartości takiej samej jak boostery, ale tworzone z kart, które zostały już “otwarte”. W praktyce można to wykorzystać do bardzo tanich (ok. 6-10 zł zamiast 30-40) booster draftów, gdzie co prawda nie ma szans trafić mocarnych kart, ale jest sporo zabawy i doskonalenia strategii przy grze. Drugi powód napisania programu był typowo informatyczny – chęć doskonalenia swoich umiejętności w zakresie “czystego” programowania obiektowego (z uwzględnieniem wszystkich [no dobrze, może części (niewielkiej)] zasad OOP-u) oraz dziewicze wykorzystanie narzędzia Doxygen do generowania dokumentacji. Przyznaję, że oba eksperymenty wyszły po mojej myśli, a Doxygen okazał się bardzo przyjemnym narzędziem (choć zaburzył moją estetykę kodu – chlip). Jakie są efekty tego projekciku – dowiecie się pewnie już wkrótce. Oczywiście, udostępnie cały kod wraz z projektem w VC++ oraz dokumentacją w formacie HTML (coś ala dokumentacja Ogre’a 3D, ale dużo mniejsza).

Pozdrawiam i dziękuję – SceNtriC.

piątek, 13 listopada 2009

Niedziałający algorytm – ale coś w sobie ma

W trzecim semestrze mamy przedmiot o znamiennej nazwie Optymalizacja Kombinatoryczna. Jak nietrudno się domyślić, jest to dalsza część tematu powiązanego z problemami i algorytmami je rozwiązującymi, jednak tym razem całość krąży wokół szukania rozwiązań optymalnych dla problemów NP-trudnych i silnie NP-trudnych (należących do tzw. NP-zupy). Strasznie zagmatwana dziedzina i do tego bardzo teoretyczna – potrafi być miażdżąca dla umysłu, ale jak się w to wgłębić, to jest dosyć ciekawa (pod warunkiem, że nie trzeba pisać z tego kolokwium). Tym bardziej, że u nas jest bardzo przystępnie tłumaczona (pozdrawiam wykładowcę).

Zadaniem części studentów na laboratoriach jest napisanie rozwiązań do tzw. problemu Job Shop. Polega on w skrócie (i intuicyjnie) na tym, iż mamy M maszyn oraz N zadań do wykonania, dla których określone są dwójki (m0 t0) (m1 t1) … (mn tn), gdzie mi to indeks maszyny, którą potrzebuje dane zadanie, a ti to ilość kwantów czasu, które musi spędzić zadanie na maszynie mi. Etap “produkcji” danego zadania (czyli taka dwójka) musi być wykonany kolejno – najpierw musi przejść pierwszą wymienioną maszynę, potem drugą, trzecią itd. Nie można zmieniać kolejności. Jest też jedna ważna sprawa, przez którą poniższy algorytm działa niepoprawnie (choć będzie poprawny dla innych form tego problemu) – jeżeli dane zadanie dostanie maszynę do dyspozycji, to spędza na niej tyle czasu, ile potrzebuje – nie oddaje jej przed końcem danego procesu (trzyma się kurczowo nóżkami).

Jest to zatem jedna z odmian problemu szeregowania. Jakby tego było mało, jest to jeden z rodzajów bardzo znanego problemu komiwojażera, w którym miasta do odwiedzenia to zadania (a ich liczba N), a maszyna jest jedna i jest to nasz podróżnik.

Jak już wcześniej wspomniałem, jeżeli zadanie dostanie maszynę, to nie może się od niej oderwać przed ukończeniem danego etapu produkcji. Jest to zatem przykład niewywłaszczalności. Poniższy pomysł na algorytm zakłada jednak, że jeżeli nastąpią pewne okoliczności, jedno zadanie może przerwać swój etap i dopuścić maszynę do drugiego zadania. Jest to zatem system wywłaszczalny i w dodatku taki, w którym najwyższy priorytet mają zadania o najmniejszym indeksie.

Cóż, troszkę formalizmu, a teraz konkrety. Muszę z góry przyznać, iż algorytm jest dosyć kiepski – nie działa zbyt optymalnie. Ma jednak taką właściwość, iż jest bardzo prosty i nawet ja umiałem go zaimplementować. A poza tym, przedstawiam ten pomysł jako inspirację dla kogoś, kto być może wymyśli (albo chociaż zna) działający i optymalny algorytm dla Job Shopa. W garści mam też pomysł oparty na algorytmie SJF, ale wolałbym implementować “mądrzejsze” rozwiązania (algorytmy genetyczne, inne metaheurystyki, B&B, itd.)

Może mały przykład. Mamy trzy maszyny do dyspozycji (o indeksach od 0 do 2) oraz trzy zadania (0-2), które zostały zdefiniowane następująco:

T0: (0 2) (1 3) (2 1)

T1: (1 1) (2 2) (0 1)

T2: (1 3) (0 2) (2 3)

Opiszę może słownie jedno z zadań, żeby wszystko było całkowicie jasne – zadanie nr 2 najpierw musi spędzić trzy kwanty czasu na maszynie nr 1, potem przez dwa kwanty czasu jest wykonywane na maszynie nr 0, a na końcu odwiedza maszynę nr 2 i zostaje tam na trzy kwanty.

Uszeregowanie, jakie proponuje opisywany algorytm, wygląda tak:

jsp1

Oczywiście, widać, iż nie jest to zbyt optymalne rozwiązanie – zwłaszcza dla zadania drugiego, które smutne i zmechacone powolutku człapie od jednej maszyny do drugiej, w międzyczasie ustępując miejsca zadaniu zerowemu, które ma niższy indeks. W efekcie długość uszeregowania wszystkich zadań wynosi 12 kwantów czasu. Czasami naprawdę się zastanawiam, po co opisuję niedziałające algorytmy. Może dlatego, że są tak proste, że łatwo się o nich pisze notki.

Pierwszą rzeczą, jaką należy wykonać, jest wykorzystanie kolejek FIFO do trzymania informacji o zadaniach, ale w specyficzny sposób. Mając zadanie, które opisane jest jako:

(1 2) (0 1) (2 3)

musimy utworzyć kolejkę o wartościach:

1 1 0 2 2 2

Widać, że na maszynie nr 1 musimy spędzić dwa kwanty czasu (są dwie jedynki), na zerowej jeden, a na drugiej – 3 kwanty. Tak przygotowane kolejki następnie wykorzystujemy w algorytmie i stopniowo zdejmujemy z nich wartości. Ale może najpierw schemat, a nie, że ja tutaj tak szybko myk-myk.

1. Wszystko dzieje się w pętli, która odlicza kolejne kwanty czasu. Jej zakończenie jest uwarunkowane przez stan zmiennej logicznej typu bool.

2. Tworzymy sobie tablicę tf o typie int i rozmiarze N i zapełniamy ją zerami.

3. Robimy sobie herbatę.

4. Tworzymy pętlę dla każdej maszyny.

5. W każdej iteracji tej pętli tworzymy następną pętlę (z licznikiem t), w której sprawdzamy wszystkie zadania, począwszy od zerowego. Jeżeli jakieś zadanie t nie zostało w tym kwancie “wykorzystane” (tf[t] == 0), jego kolejka nie jest pusta, a pierwszy element to indeks aktualnie przetwarzanej maszyny – tf[t] = 1, zapamiętujemy t, zdejmujemy wartość z kolejki zadania t oraz wychodzimy z pętli.

6. Zapisujemy do wektora aktualnie przetwarzanej maszyny wartość t. Jeżeli jednak żadne zadanie nie potrzebuje maszyny w danym kwancie czasu, wpisujemy –1 (jakieś oznaczenie musimy przyjąć).

7. Sprawdzamy (już poza pętlą z punktu 4.), czy kolejka któregokolwiek zadania nie jest pusta. Jeżeli któreś zadanie ma jeszcze jakieś wartości w kolejce – przechodzimy do następnej iteracji pętli zliczającej kwanty czasu. W przeciwnym razie – kończymy algorytm.

W ten sposób, naszym rozwiązaniem będą wektory kolejnych indeksów zadań, które są wykonywane na danej maszynie w określonym kwancie czasu (lub –1, jeżeli maszyna nie jest wykorzystywana). Polecam też wykonywać punkt 3. jedynie raz – potem Wam się namnożą herbaty.

Algorytm jest bardzo prosty, choć nie daje zadowalającego wyniku dla szeregowania z wywłaszczaniem. Nie działa też jakoś nienaturalnie wolno, choć złożoność mówi co innego – O(N*M*i), gdzie i to ilość kwantów czasu, jaka jest potrzebna na nasze uszeregowanie. A że i przy dużych instancjach dąży do nieskończoności…

Na koniec pełny kod naszego rozwiązania (QUANTITY to N, a MAC_QUANTITY to M).

   1: #include <cstdio>
   2: #include <cstdlib>
   3: #include <vector>
   4: #include <queue>
   5: #include <ctime>
   6: #include <cctype>
   7:  
   8: #define QUANTITY 3
   9: #define MAC_QUANTITY 3
  10:  
  11: int main (int argc, char* argv[])
  12: {
  13:     // wrzucenie zadań do kolejek
  14:     // jeżeli jakieś zadanie ma być wykonywane:
  15:     // na 1-szej maszynie 2 kwanty czasu, a potem
  16:     // na 2-giej maszynie 3 kwanty czasu, to
  17:     // obraz kolejki:
  18:     // 1 1 2 2 2
  19:     std::queue<unsigned> task[QUANTITY];
  20:     std::vector<int> machine[MAC_QUANTITY];
  21:  
  22:     // zadanie 0
  23:     task[0].push(0);
  24:     task[0].push(0);
  25:     task[0].push(1);
  26:     task[0].push(1);
  27:     task[0].push(1);
  28:     task[0].push(2);
  29:  
  30:     // zadanie 1
  31:     task[1].push(1);
  32:     task[1].push(2);
  33:     task[1].push(2);
  34:     task[1].push(0);
  35:  
  36:     // zadanie 2
  37:     task[2].push(1);
  38:     task[2].push(1);
  39:     task[2].push(1);
  40:     task[2].push(0);
  41:     task[2].push(0);
  42:     task[2].push(2);
  43:     task[2].push(2);
  44:     task[2].push(2);
  45:  
  46:     // odliczamy kolejne kwanty czasu
  47:     bool end = false;
  48:     int i;
  49:  
  50:     for (i = 0; !end; ++i)
  51:     {
  52:         int tf[QUANTITY] = { 0 }; // jeżeli danego zadania jeszcze nie było w określonym kwancie czasu
  53:  
  54:         // dla każdej maszyny bierzemy pierwsze zadanie, które ją wymaga
  55:         for (int j = 0; j < MAC_QUANTITY; ++j)
  56:         {
  57:             int t; // zachowujemy numer zadania
  58:  
  59:             for (t = 0; t < QUANTITY; ++t)
  60:             {
  61:                 // jeśli coś jeszcze zostało do zrobienia w danym zadaniu (kolejka nie jest pusta)
  62:                 // oraz zadanie nie zostało już gdzieś "włożone" w danym kwancie czasu
  63:                 if (!task[t].empty() && tf[t] == 0)
  64:                 {
  65:                     // jeśli pierwszy element to indeks danej maszyny
  66:                     if (task[t].front() == j)
  67:                     {
  68:                         tf[t] = 1;
  69:                         task[t].pop();
  70:                         break; // kończymy pętlę
  71:                     }
  72:                 }
  73:             }
  74:  
  75:             // jeżeli t zmieściło się w pętli, to zapisujemy indeks
  76:             // zadania do wektora danej maszyny - w przeciwnym razie
  77:             // zapisujemy -1
  78:             if (t < QUANTITY)
  79:             {
  80:                 machine[j].push_back(t);
  81:             }
  82:             else
  83:             {
  84:                 machine[j].push_back(-1);
  85:             }       
  86:         } // for (int j = 0; j < MAC_QUANTITY; ++j)
  87:  
  88:         bool e = true;
  89:  
  90:         // jeżeli kolejka któregokolwiek zadania nie jest pusta,
  91:         // to jeszcze nie kończymy algorytmu
  92:         for (int t = 0; t < QUANTITY; ++t)
  93:         {
  94:             if (!task[t].empty())
  95:             {
  96:                 e = false;
  97:                 break;
  98:             }
  99:         }
 100:  
 101:         end = e;
 102:     } // for (i = 0; !end; ++i) 
 103:  
 104:     for (unsigned i = 0; i < MAC_QUANTITY; ++i)
 105:     {
 106:         printf("Maszyna %d: ", i);
 107:  
 108:         std::vector<int>::iterator it;
 109:  
 110:         for (it = machine[i].begin(); it != machine[i].end(); ++it)
 111:         {
 112:             printf("%d ", *it);
 113:         }
 114:         printf("\n");
 115:     }
 116:  
 117:     printf("\n");
 118:  
 119:     printf("Łączny czas uszeregowania procesów: %d\n", i);
 120:    
 121:     getchar();
 122:     return 0;
 123: }

Pozdrawiam i dziękuję - SceNtriC

środa, 11 listopada 2009

Małe aktualności ze świata gier i oczywiście Wielki Mistrz

Ostatnio niewiele tu pisałem na tematy niezwiązane bezpośrednio z Wielkim Mistrzem. Ta notka też nie będzie całkowicie pozbawiona informacji o naszym cRPG-u – wczoraj pojawiła się mała aktualizacja, która poprawia parę niedoróbek fabularnych i przede wszystkim oferuje większy plecak. Zamiast przywoływać linki, pozwolę sobie przywołać post z forum Warsztatu, w którym znajdują się odnośniki do poszczególnych wersji – znajdziecie pod nimi aktualną wersję:

A oto te linki

Należałoby jednak wspomnieć o dwóch wydarzeniach. Pierwszym – bardzo ważnym w środowisku gier komputerowych i drugim nieco mniej istotnym, ale ciekawym.

Pierwsza sprawa to oczywiście decyzja Epic Games o wypuszczeniu na wolność Unreal Engine 3. Może za bardzo Was zachęciłem, więc uściślę – gracze otrzymali Unreal Development Kit, który może być używany przez firmy do tworzenia komercyjnych gier. Jest oczywiście pewien haczyk – dochód do 5000$ nie wymaga posiadania licencji od Epica, natomiast każdy zysk ponad ten próg wymaga zapłacenia 25% od nadmiarowego dobra. Muszę przyznać, że nie próbowałem się tym zajmować i prawdopodobnie w najbliższej przyszłości nie będę miał czasu i chęci. Nie jest to też silnik w pełnym tego słowa znaczeniu – nie otrzymujemy źródeł, ale narzędzia (edytory), które pozwalają nam na stworzenie gry w oparciu o możliwości Unreal Engine 3 – między innymi skrypty do dyspozycji mamy język skryptowy UnrealScript. Jak to napisał Regedit na swoim blogu – jest to taki Game Maker, tylko bardziej zaawansowany. Ciekawa inicjatywa – wygląda na to, że firmy szukają najwytrwalszych jednostek wśród społeczeństwa programistów, którzy w przyszłości mogliby zasilić ich szeregi. A jeżeli ktoś chce się pobawić, to również ma doskonałą okazję, żeby zrobić coś ciekawego. Jeżeli ktoś chce poczytać wątek na forum Warsztatu, to nie musicie już go szukać.

Druga sprawa to nowa inicjatywa Google. Jak wiadomo, ta firma szybko wkracza w nowe dziedziny życia informatycznego – zaczęło się od wyszukiwarki, potem przyszła pora na pocztę elektroniczną, arkusze, mapy, przeglądarki, wkrótce dostaniemy system operacyjny, a teraz możemy pobawić się językiem programowania Go. Tylko czekam, aż u rzeźnika zobaczę kiełbasy sygnowane logiem Google – żartuję, inicjatywa bardzo mi się podoba (choć GoogleMeat bym nie zjadł). Nie przeglądałem za bardzo projektu, ale muszę przyznać, że nie podoba mi się troszkę składnia nowego języka. Zresztą sami popatrzcie:

05    package main
07 import (

08 "./file";
09 "fmt";
10 "os";
11 )
13 func main() {
14 hello := []byte{'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n'};
15 file.Stdout.Write(hello);
16 file, err := file.Open("/does/not/exist", 0, 0);
17 if file == nil {
18 fmt.Printf("can't open file; err=%s\n", err.String());
19 os.Exit(1);
20 }
21 }

Być może jestem za bardzo przyzwyczajony do składni C-podobnej, ale pisanie pascalowego “:=” przy przypisywaniu wartości uważam za zbyteczne. Choć to może tylko takie pobieżne spojrzenie – na pewno język został przemyślany i możemy się spodziewać kilku ciekawych rozwiązań (tak, zawsze tak mówią).

Z tego, co udało mi się przeczytać na wyżej podlinkowanej stronie, Google nie ukrywa, iż Go jest eksperymentem, a nie próbą zawładnięcia “rynkiem” języków programowania. Cechuje się podobno szybką kompilacją, garbage collectorem, brakiem konieczności dołączania wielu plików nagłówkowych, wsparciem wielu rdzeni i nie tak ścisłym typowaniem. Powiem uczciwie – więcej mi się nie chciało czytać. Jeżeli ktoś jest ciekawy, to polecam jeszcze raz zajrzeć pod link, który podałem wcześniej – są tam tutoriale, dokumentacja i sposób instalacji. A tutaj wątek na forum Warsztatu.

Cóż, dzisiejsza notka może mało wylewna, ale w sumie nie ma o czym pisać. Postaram się coś naskrobać w najbliższym czasie.

Pozdrawiam i dziękuję – SceNtriC.

niedziela, 1 listopada 2009

Wielki Mistrz nadszedł

screenshot_10312009_113223668 A przynajmniej jego prawie-że-finalna wersja. Będziemy uwzględniać wszystkie uwagi jakie pojawią się po release’ie i w miarę możliwości sprostać oczekiwaniom graczy. Dlatego nie mogę jeszcze powiedzieć o ostatecznej (i definitywnej) wersji. Ale jesteśmy bardzo blisko.

Poniżej widzicie linki do poszczególnych wersji tego wydania gry. Możecie teraz kliknąć, a potem czytać dalszą część notki w czasie ściągania aplikacji.

Standardowym zwyczajem – wypunktowanie najważniejszych nowinek i cech naszego “produktu”. Tak, chyba tak można nazwać, więc bez cudzysłowów – produktu.

  • Nowa fabuła, historia, dialogi, etc.
  • Mapa
  • Dziennik
  • Nowe przedmioty
  • I czary też
  • Oświetlenie
  • Nowe bloczki w lochach
  • Sztuczna inteligencja potworów
  • Nowe modele
  • Baza dźwiękowo-muzyczna o kryptonimie T.R.A.L.A.L.A.
  • Pełno różnych drobnostek, które uprzyjemniają grę
  • Instalator (opcjonalny)

Być może mało tych punktów, ale są to ogólniki, z których większość mogłaby zostać rozwinięta w kolejne podpunkty.

Jeśli chodzi o fabułę, dialogi, zadania, klimat to pozwólcie, iż nie screenshot_10312009_114044858 będę się tu wypowiadał – w poprzednich notkach troszeczkę już o tym pisałem i powtarzanie się tutaj byłoby nader nużące. Dopowiem tylko, iż pełnoprawnych rozmów jest około 60 (jak nie więcej), ilość zadań krąży wokół 30, a liczba easter eggów i absurdów pewnie dąży do nieskończoności. Doszła mała ciekawostka – od pewnego momentu w grze gracz ma do dyspozycji swoją komnatę, w której może przechowywać rzeczy niemieszczące się w plecaku. Wspomnę też, iż możliwe są minimum dwa zakończenia, co sprawia, że warto grę przejść parę razy.

screenshot_10312009_114047623 O wiele ważniejsza dla graczy okaże się pewnia mapa oraz dziennik. Obie nowości znacznie ułatwią rozgrywanie gry i orientację w lochach, czyli coś, na co gracze bardzo narzekali. Teraz będzie można z większym prawdopodobieństwem określić swoją lokalizację oraz dowiedzieć się, jakimi zadaniami tak naprawdę zostaliśmy obarczeni.

Nowe przedmioty – trochę ich doszło. Niektóre nie są może do końca nowe, ale dostały nowe cechy, które sprawiają, iż są użyteczne (ale dziwne zdanie). W dodatku, część “ajtemów” może być wykorzystywana wielokrotnie. Paleta broni również została rozszerzona (choć nie w sposób graficzny) i podzielona na trzy klasy. Doszły też nowe czary (jak chociażby teleport) i zdolności bohatera. Warto wspomnieć o tym, że w przeciwieństwie do Heretic Dema liczniki złota i doświadczenia zostały wyraźnie rozdzielone. Chociażby dlatego, że pojawił się handel – nie spodziewajcie się pod tym względem cudów na miarę Diablo II, ale w każdym cRPG-u handel się przyda.

Ważną nowinką, tym razem technologiczną, jest oświetlenie, screenshot_10312009_203639043 które niesamowicie polepszyło graficzny odbiór gry. Te podziemia wyglądają w końcu jak prawdziwe lochy – jest ciemno i tylko gdzieniegdzie ukazują się maleńkie poświaty pochodzące od pochodni umieszczonych na ścianach. Tworzy to ciepły klimat (ogień w końcu do zimnych nie należy) i podwyższa radość z gry. Wszystkiego dopełnią nowe kaflobloczki – zapomnijcie o tych z Heretica. Teraz będziecie mogli stanąć na skraju zawalonego mostu, zajrzeć do studni, oprzeć się o półokrągłe mury i zachwycać się niecodziennym sklepieniem.

Kolejną rzeczą, na którą zwracali nam uwagę gracze to blokowanie się potworków na rogach korytarzy przez co walka była banalna. W nowej wersji został zaimplementowany system wyszukiwania drogi, który pozwala stworkom na samodzielne szukanie dojścia do zagryzienia gracza i niestraszne są im krawędzie ścian. Co prawada, nie zawsze system działa idealnie, ale bądźcie pewni, że hasając sobie wesoło po lochach może Was szturchnąć od tyłu jakiś gad, zapytać o godzinę i odgryźć Wam rękę zanim powiecie, że zostawiliście zegarek w domu.

screenshot_10312009_205843071 Pojawiły się też nowe modele – stoły, krzesła (wiem, że w lochach może się to wydawać dziwne, ale technologia drewna jest tu na całkiem niezłym poziomie), lada w tawernie (a nie mówiłem?), piec do pieczenia chleba, gobeliny, wazy oraz cztery modele humanoidalno-potworowe. Z pewnością o czymś zapomniałem – aha, między innymi o kowadle i młocie kowalskim.

Punktem, który będzie poszerzany w dalszych wersjach finalnej odsłony Wielkiego Mistrza będzie baza dźwiękowa. W chwili obecnej podczas gry leci całkiem przyjemna muzyka, a większość obiektów w grze wydaje odpowiednie odgłosy (“Tup tup”, “Aaargh!”, “Tylko nie moje lukrowane guziczki!”). Nie wszystkie jednak – miejmy nadzieję, że na tym polu uda nam się powiększyć zasoby.

Oczywiście, oprócz rzeczy wymienionych powyżej w Wielkim Mistrzu poprawiono wiele drobnostek. Zmieniono wygląd HUD-a gracza, wybalansowano potwory i bronie, zablokowano ruch gracza podczas zadawania ciosów (dzięki czemu gra nie jest już taka łatwa), dodano parę linijek do listy (nie)płac, dopisano instalator (nieszkodliwy dla systemu), zaimplementowano obracanie się NPC-ów… Troszkę sie tego zebrało przez cztery miesiące.

Najważniejsze jest jednak to, iż możecie pograć w tą prawie-że-finalną wersję i zobaczyć, co można zrobić w ciągu kilkunastu miesięcy komunikując się jedynie przez Internet. Ten projekt to naprawdę wspaniałe doświadczenie i możliwość zobaczenia, jak to wygląda od tej drugiej strony (i dlaczego nie jest aż tak różowo). Jeżeli ściągniecie, pogracie i gra Wam się spodoba – będziemy szczęśliwy. Jeśli będziecie mieli jakieś uwagi – również będziemy szczęśliwy, że komuś zależy, aby Wielki Mistrz był aplikacją pozbawioną wad.

Wyszło dosyć patetycznie, a sama gra jest przecież niepozbawiona specyficznego humoru. Zdajemy sobie sprawę, iż nie każdemu będzie on pasował, ale absurdalnych cRPG-ów nie ma chyba za dużo na rynku. Trzeba zapełniać nisze amatorskimi projektami.

Na koniec (choć powinienem to zrobić wcześniej) mała rekomendacja. Otóż mój kolega z roku o nicku Witoj (pozdrawiam) urzeczywistnia pomysł, jaki przyszedł mu kiedyś do głowy (choć ja też gdzieś się tam kręciłem o ile dobrze pamiętam – przepraszam za brak skromności) i powoli tworzy świat Całkownika, w którym matematyka nie jest tak spokojna jak w naszej rzeczywistości. Powstały na razie dwie części – nie są one może jeszcze poziomu Bułhakowa, ale kolega powoli się rozkręca. Miejmy nadzieję, że powstanie książka oraz – docelowo taki jest zamiar – gra oparta na Całkowniku. Oto linki do rzeczonych tekstów – część pierwsza i druga. Polecam

Tymczasem zachęcamy do ściągania, grania i komentowania Wielkiego Mistrza. Mamy nadzieję, że spędzicie przy nim kilka radosnych godzin. I będziecie zajadać się udkami kurczaka w grze – bynajmniej nie gumowego.

Pozdrawiam i dziękuję – SceNtriC.

Ps. Jeżeli przy używaniu mieczy nastąpiłby duży spadek wydajności, możecie ściągnąć tą łatkę i rozpakować do katalogu z Wielkim Mistrzem.