Forumowe RPG!

0

@Proxima na Ubuntu nie pójdzie za nic. Jakiś komunikat błędu a biblioteki przekopiowałem do /usr/lib, ja tu nie dojdę co i jak. Z wersją pod Windows nie byłoby problemów.

komunikat błędu:

./Main: undefined symbol _ZN2sf12RenderWindowC1ENS_9VideoModeERKNS_6StringEjRKRS_15ContextSettingsE

Nie dojdę za nic. Tylko że ja rozpakowywałem pliki so z archiwów rpm pod OpenSUSE, nie wiem czy to też pod Ubuntu pójdzie i czy to prawidłowy format bibliotek. To export LD_LIBRARY_PATH też nic nie dało. :-(

1

@Proxima, @Trebuh, reszta projektu - voilà.

Zasady/informacje:

  • Wątków wam żadnych tu nie zakładam, organizujcie podforum jak chcecie :P.
  • Jakiś minimalny ruch tutaj sugerowany
  • Z wielką mocą przychodzi wielka odpowiedzialność
  • Podforum eksperymentalne - jeśli nie będzie w ogóle ruchu albo projekt umrze to trudno, ale nic nie szkodzi bo po prostu wszystko się przeniesie do społeczności.
  • Jakieś wątki jeszcze tu przenieść? Wydaje mi się że to wszystko.
  • Chyba nie zepsułem forum podczas operacji. Na wszelki wypadek, od 2 w nocy do rana trochę czasu jest...

Dla reszty forum, zaskoczonej stworzeniem nowego działu:

  • jeśli projekt się uda i podforum się sprawdzi, zawsze jakiś sukces dla forum, oraz lepiej wszystko mieć w jednym miejscu
  • jeśli projekt się nie uda/umrze przedwcześnie albo z innego powodu skończy, wszystko stąd się przeniesie do społeczności i nic na tym forum nie straci.

To chyba tyle - jeszcze wkleiłem te "zasady" do przyklejonego wątku w dziele

0

Łoo, dzięki :D

1

Drobny UP.
Dodany doxygen.
Repo jednak 4programmers :P.
Troche wprawy i git sie coraz łatwiejszy robi :)
http://4programmers.github.io/4pRPG/index.html
https://github.com/4programmers/4pRPG/tree/master

0

A mnie coś nie gra:

Tak dobrze już wszystko działa, piknie... 9 commitów? Czegoś nie zauważam? :D

3

Up.
OD RAZU MÓWIE ŻE FUNKCJA MAIN W REPO TO TAKI WIELKI POLIGON, docelowo będzie to ładniejsze ;>
Szczwany ja usunąłem poprzednie posty żeby nie było double znowu.
Dziś opowiem jak to działa.
Projekt jest rozwijany nadal, mam oczywiście szkołe ale i tak dosyć sprawnie idzie.
Kod silnika pisze jak na razie tylko ja, reszta czeka na skończenie go i wtedy bierzemy sie za gre.
To co doszło to:

Okienka z chmurkami, jescze nie dopicowane.

user image

Dialogi oparte na drzewach n-arnych, wczytywane rekurencyjnie, co do głębokości to.. Nie mam pojęcia, pewnie dopókie sie nie wywali stos.

user image
user image
Dialogi były jedną z ciekawszych rzeczy z którymi miałem spory problem, ale to dobrze, bo przynajmniej czegoś sie nauczyłem :)
Struktura pliku z dialogami wygląda tak, gdzie musi być sekwencja
Reply( rozpoczyna rozmowe )
Potem player->reply->player->reply, i tak dalej.
Ogólnie "format" wygląda dosyć brzydko przy bardziej rozbudowanym dialogu, ale jest łatwy w edycji, strukture można zaobserwować na dialogach nr 2 i 3 bo są krótsze.
condition to warunek który będzie musiał być spełniony aby odpowiedź była widoczna, i będe robił coś w stylu VM która będzie to obsługiwać.
action natomiast to akcja którą wykonuje npc i enum od akcji wygląda tak

<?xml version="1.0" encoding="UTF-8"?>
<dialogs>
	<npc id="1">
     <reply text="Witaj!">
      <player text="Witaj magu!">
       <reply text="Chcesz questa?">
        <player text="Tak">
         <reply text="Na moczarach są złote kalesony, przynieś je!">
          <player text="Podejme się!" condition="level > 10">
           <reply text="A więc idź, czekam!" action="3" questname="moczary0">
           </reply>
          </player>
          <player text="Nie interesuje mnie to zadanie">
           <reply text="Cóż, szkoda" >
           </reply>
          </player>
         </reply>
        </player>
        <player text="Nie">
         <reply text="Twoja strata :P">
         </reply>
        </player>
        <player text="Co dostane w zamian?">
         <reply text="Nagrode, bardzo chojną">
         </reply>
        </player>
       </reply>
      </player>
      <player text="Dawaj itemy" >
       <reply text="Czy to napad?">
        <player text="Tak" condition="strength > 50">
         <reply text="Okej koksie nie bij, masz" action="1" params="103,22,45,125,1024">
         </reply>
        </player>
        <player text="Nie">
         <reply text="Uff, to dobrze">
         </reply>
        </player>
        <player text="Być może">
         <reply text="Żadam dokładnej odpowiedzi">
          <player text="Tak">
           <reply text="Więc walcz!">
           </reply>
          </player>
          <player text="Nie">
           <reply text="Uff, to dobrze">
            <player text="Nom">
             <reply text="Hiho">
              <player text="Co?">
               <reply text="Nic">
                <player text="Może jednak coś?">
                 <reply text="Nie, nic">
                  <player text="Na pewno?">
                   <reply text="No, na pewno">
                   </reply>
                  </player>
                  <player text="Daj piniążek">
                   <reply text="Nie mam :(">
                    <player text="Masz masz">
                     <reply text="Jakbym miał, i tak bym nie dał">
                     </reply>
                    </player>
                    <player text="No rozumiem, bida w krainie">
                     <reply text="Niestety">
                      <player text="No daj dolara">
                       <reply text="No nie mam, serio">
                        <player text="maszmaszmaszmasz">
                         <reply text="Dobra żebraku, masz 10 golda i ić sobie">
                          <player text="Dziękuje Ci">
                           <reply text="Idź już">
                           </reply>
                          </player>
                          <player text="A dej jescze 10 golda">
                           <reply text="O ty chamie, walcz!">
                           </reply>
                          </player>
                          <player text="Daj jescze plix">
                           <reply text="Ile?">
                            <player text="1 zet">
                             <reply text="Tyle Ci moge dać">
                             </reply>
                            </player>
                            <player text="3 zeta">
                             <reply text="Okej, ale nie pokazuj sie tu przez tydzień!">
                             </reply>
                            </player>
                            <player text="10 zeta">
                             <reply text="O ty chamie!">
                             </reply>
                            </player>
                           </reply>
                          </player>
                         </reply>
                        </player>
                       </reply>
                      </player>
                      <player text="Żegnaj">
                       <reply text="3m sie">
                       </reply>
                      </player>
                     </reply>
                    </player>
                   </reply>
                  </player>
                 </reply>
                </player>
               </reply>
              </player>
              <player text="Test1">
               <reply text="Test3">
               </reply>
              </player>
              <player text="Test2">
               <reply text="Test4">
               </reply>
              </player>
             </reply>
            </player>
           </reply>
          </player>
         </reply>
        </player>
       </reply>
      </player>
      <player text="Żegnaj">
	   <reply text="trzym sie">
	   </reply>
     </player>
     </reply>
	</npc>

	<npc id="2">
	 <reply text="Witaj w sklepie u Zbycha">
	  <player text="Witaj, co masz do sprzedania?">
	   <reply text="Spójrz">
	   </reply>
	  </player>
	  <player text="Co skupujesz?">
	   <reply text="Spójrz">
	   </reply>
	  </player>
	  <player text="Żegnaj!">
	   <reply text="Cześć">
	   </reply>
	  </player>
	 </reply>
	</npc>

	<npc id="3">
	 <reply text="Witaj :P">
	  <player text="Siema, co tam?">
	   <reply text="A dobrze, dobrze">
	   </reply>
	  </player>
	  <player text="Test">
	   <reply text="Git Test">
	   </reply>
	  </player>
	  <player text="Testowy tekst">
	   <reply text="Testowa odpowiedź ;)">
	   </reply>
	  </player>
	 </reply>
	</npc>
</dialogs>
enum ATYPE
{
  //Wszystko raczej dość logiczne, RESERVED_FIELD to pola które sobie zarezerwowałem na przyszłość
   NPC_ONLY_TALK, NPC_GIVE_ITEM, NPC_GET_ITEM, NPC_GIVE_QUEST,
   NPC_VALID_QUEST, NPC_FIGHT, NPC_TRADE, NPC_RESERVED_FIELD_0, NPC_RESERVED_FIELD_1,
   PLAYER_RESPONSE, ACTION_NOT_VALID=64
};

params to parametry liczbowe parsowane i ładowane do std::vector<int>, czyli np itemy które npc da graczowi.
Struktury z danymi pojedyńczego węzła zaprojektowałem tak, każdy NPC posiada n-arne drzewo struktur Action(dla każdego węzła przypada
jedna struktura, która będzie potem przetwarzana na czymś ala-VM i generowane będą odpowiednie sygnały np OPEN_SHOP, lub VM sama w sobie będzie miała te wszystkie okna i ona będzie je tworzyć.)
Wiem że nie jest to super-wydajne rozwiąnie, ale nie wiem w sumie czy przy dzisiejszej mocy i ilości pamięci komputerów faktycznie takie coś jest problemem, wydaje mi sie - że nie, nie ukrywam że dynamiczne zarządzanie drzewem byłoby trudniejsze do zrobienia, ale nic, czekam na wasze opinie, jeśli to jest fe - poprawie to :)

struct HelpInfo
{
	HelpInfo()
	{}
	HelpInfo(std::string _cond)
	: helpstring(_cond)
	{}
	HelpInfo(const HelpInfo& r)
	{
		this->additdata = r.additdata;
		this->helpstring = r.helpstring;
	}
	HelpInfo& operator=(const HelpInfo& rhs)
	{
		this->additdata = rhs.additdata;
		this->helpstring = rhs.helpstring;
		return *this;
	}
	std::vector<int> additdata;
	std::string 	 helpstring;
};
struct Action
{
	Action()
	: type_action(NPC_ONLY_TALK)
	, ad_info(){}
	Action(std::wstring t, ATYPE at, HelpInfo hi){
		text = t;
		type_action = at;
		ad_info = hi;
	}
	Action(const Action& r){
		this->type_action = r.type_action;
		this->ad_info = r.ad_info;
		this->text = r.text;
	}
	void clean(){
	    type_action = NPC_ONLY_TALK;
	    ad_info.helpstring.clear();
	    ad_info.additdata.clear();
	}
	ATYPE 		 type_action;
	HelpInfo 	 ad_info;
	std::wstring text;
};

Pomyślałem również że może ktoś/ja kiedyś będe chciał skorzystać drugi raz z niektórych pomysłów, więc wczytywanie i parsowanie danych, oraz formatowanie danych w chmurce, uczyniłem strategiami, które wyglądają tak.

class IDataFormat
{
public:
    IDataFormat(){};
    virtual void format(const ItemData, const sf::Vector2f&,unsigned int&, sf::Font&, std::vector<sf::Text>&) = 0;
    virtual ~IDataFormat(){};
};
class IDataRead
{
public:
    IDataRead(){};
    virtual void read(TiXmlElement*) = 0;
    virtual Action get() = 0;
    virtual ~IDataRead(){};
};

Przykładowo obiekt dziedziczący z IDataFormat(), formatuje dane w chmurce w taki sposób.
Gdzie stricte CAŁE dane nt ułożenia, koloru itp, są przetwarzane na tej funkcji.
Wywoływana ona jest dosyć czytelnie(chyba :p) w taki sposób

// Wywoływane w main, co iteracje odświeżane, wiem że możnaby zrobić to
// W stylu "refresh-if-needed", ale jak narazie IMO to chyba przedwczesne kombinacje-optymalizacje by były.
void EquipmentWindow::controlCloud(sf::Vector2i vct)
{
    // Jeśli mysza najedzie na item, gid będzie niezerowe.
    unsigned int gid = getGID(vct);
    if(gid)
    {
        // czyszczone
        descriptions.clear();
       // przetwarzane
        formatter.format(_imgr.getData(gid), cloud.getPosition(),cloud_border,font,descriptions);
        hoover = true;
        cloud.setPosition(sf::Vector2f(vct.x+15, vct.y));
        return;
    }
    hoover = false;
}
void EquipFormat::format(const ItemData itm, const sf::Vector2f& cloud_pos,unsigned int &border,sf::Font& font,std::vector<sf::Text>& desc)
{
    std::basic_string<sf::Uint32> utf32;
    sf::Color col;
    sf::Utf8::toUtf32(itm.name.begin(), itm.name.end(), std::back_inserter(utf32));
    sf::Text some_name(utf32, font, 15);
    switch(itm.quality)
    {
        case 0: col = sf::Color::Blue; break;
        case 1: col = sf::Color::Black; break;
        case 2: col = sf::Color::Yellow; break;
        case 3: col = sf::Color::Red; break;
    }
    some_name.setColor(col);
    some_name.setPosition(cloud_pos.x, cloud_pos.y);
    desc.push_back(some_name);
    switch(itm.type)
    {
        case WEAPON:
        utf32.clear();
        utf32 = to32UTF<std::string>("Atak:");
        utf32 += to32UTF<std::string>(std::to_string(itm.attack));
        some_name.setString(utf32);
        some_name.setCharacterSize(13);
        some_name.setPosition(cloud_pos.x+border, cloud_pos.y+16);
        some_name.setColor(sf::Color::Red);
        desc.push_back(some_name);
        utf32.clear();
        utf32 = to32UTF<std::string>("Obrona:");
        utf32 += to32UTF<std::string>(std::to_string(itm.defence));
        some_name.setString(utf32);
        some_name.setColor(sf::Color::Green);
        some_name.setPosition(cloud_pos.x+border, cloud_pos.y+(14*2));
        desc.push_back(some_name);
        utf32.clear();
        utf32 = to32UTF<std::string>("Szybkość:");
        utf32 += to32UTF<std::string>(std::to_string((int)itm.speed));
        utf32 += to32UTF<std::string>("%");
        some_name.setString(utf32);
        some_name.setColor(sf::Color::Cyan);
        some_name.setPosition(cloud_pos.x+border, cloud_pos.y+(14*3));
        desc.push_back(some_name);
        break;
        case ARMOR:
        utf32.clear();
        utf32 = to32UTF<std::string>("Obrona:");
        utf32 += to32UTF<std::string>(std::to_string(itm.defence));
        some_name.setString(utf32);
        some_name.setCharacterSize(13);
        some_name.setPosition(cloud_pos.x+border, cloud_pos.y+16);
        some_name.setColor(sf::Color::Green);
        desc.push_back(some_name);
        break;
        case RECOVERY:
        utf32.clear();
        utf32 = to32UTF<std::string>("Siła odnawiania:");
        utf32 += to32UTF<std::string>(std::to_string(itm.power));
        utf32 += to32UTF<std::string>("%");
        some_name.setString(utf32);
        some_name.setColor(sf::Color::Yellow);
        some_name.setCharacterSize(10);
        some_name.setPosition(cloud_pos.x+border, cloud_pos.y+16);
        desc.push_back(some_name);
        break;
        default:
        break;
    }
    utf32.clear();
    utf32 = to32UTF<std::wstring>(itm.description);
    some_name.setString(utf32);
    some_name.setCharacterSize(13);
    some_name.setColor(sf::Color::Yellow);
    some_name.setPosition(cloud_pos.x, cloud_pos.y+(16*4));
    desc.push_back(some_name);
}

Natomiast wczytywanie/parsowanie węzłów drzewa rozwiązane zostało tak.
Oto rekurencyjna funkcja wczytująca drzewo dialogów, dane przetwarzane są w funkcji read, i pobierane funkcją get.

void NpcManager::loadTree(TiXmlElement* npc_el, NPC &npc, tree<Action>::sibling_iterator go_deeper, bool first)
{
    TiXmlElement *reply = npc_el;
    tree<Action>::iterator root;
    tree<Action>::sibling_iterator sit;
    std::string txt = reply->Attribute("text");
    Action _tmp(wide_string<std::wstring>(txt), NPC_ONLY_TALK, HelpInfo());
    if(first)
        root = npc.dialog.insert(npc.dialog.begin(), _tmp);
    if(reply->FirstChildElement("player") != NULL)
    {
        TiXmlElement *player = reply->FirstChildElement("player");
        if(first)
            sit = root;
        else
            sit = go_deeper;
        while(player)
        {
            reader.read(player);
            auto p_reply = npc.dialog.append_child(sit,reader.get());
            if(player->FirstChildElement("reply") != NULL)
            {
 		TiXmlElement* npc_quote = player->FirstChildElement("reply");
		reader.read(npc_quote);
                npc.dialog.append_child(p_reply,reader.get());
                loadTree(player->FirstChildElement("reply"), npc, p_reply, 0);
            }
            player = player->NextSiblingElement("player");

        }
    }
    else return;
}

Parsowanie rozwiązałem tak, current_processed to struktura Action w polach klasy DataRead, która pobierana jest funkcją get().
Generalnie zrobiłem tak, żeby funkcje które nie odpowiadają stricte za parsowanie, nie były tak "opasłe", co prawda mógłbym uczynić to metodą
klasy NpcManager gdzie wczytuje dane, ale przy modyfikacjach I TAK musiałbym tą klase modyfikować, a jak pisałem, nie chce tego, co najwyżej rozszerzyć strukture o odpowiednie pola.

void DataRead::read(TiXmlElement* ent)
{
    current_processed.clean();
	current_processed.text = wide_string<std::wstring>(ent->Attribute("text"));
	std::string parsed_node_type = ent->Value();
    if(parsed_node_type == "reply")
    {
        if(ent->Attribute("action") != NULL)
        {
            current_processed.type_action = (ATYPE)(atoi(ent->Attribute("action")));
            std::string params;
            if(ent->Attribute("params") != NULL)
                params = ent->Attribute("params");
            switch(current_processed.type_action)
            {
                case NPC_GIVE_ITEM:
                    parseParams(params,current_processed.ad_info.additdata,',');
                break;
                case NPC_GET_ITEM:
                    parseParams(params,current_processed.ad_info.additdata,',');
                break;
                case NPC_GIVE_QUEST:
                    if(ent->Attribute("questname") != NULL)
                        current_processed.ad_info.helpstring = ent->Attribute("questname");
                break;
                case NPC_TRADE:
                    parseParams(params,current_processed.ad_info.additdata,',');
                break;
            }
	    }
    }
    if(parsed_node_type == "player")
    {
        ATYPE type;
        if(ent->Attribute("action") == NULL)
            type = PLAYER_RESPONSE;
        else if(ent->Attribute("action") != NULL)
        {
            type = (ATYPE)atoi(ent->Attribute("action"));
            if(type < PLAYER_RESPONSE)
                type = ACTION_NOT_VALID;
        }
        current_processed.type_action = type;
        if(ent->Attribute("condition") != NULL)
            current_processed.ad_info.helpstring = ent->Attribute("condition");
    }
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1