diff --git a/bin/data/scp/gui_charselect_text.scp b/bin/data/scp/gui_charselect_text.scp index 9166e99..64329cc 100644 --- a/bin/data/scp/gui_charselect_text.scp +++ b/bin/data/scp/gui_charselect_text.scp @@ -8,7 +8,10 @@ 4=Back 5=OK 6=Cancel +7=Create +8=Cancel [2] 0=Realmlist +1=Create New Character diff --git a/bin/data/scp/race.scp b/bin/data/scp/race.scp index 3a650d3..c521ee9 100644 --- a/bin/data/scp/race.scp +++ b/bin/data/scp/race.scp @@ -6,6 +6,7 @@ name_short=Hu faction=7 name_general=Human name=Human +classmask=886 [2] model_m=51 @@ -14,6 +15,7 @@ name_short=Or faction=1 name_general=Orc name=Orc +classmask=730 [3] model_m=53 @@ -22,6 +24,7 @@ name_short=Dw faction=7 name_general=Dwarf name=Dwarf +classmask=126 [4] model_m=55 @@ -30,6 +33,7 @@ name_short=Ni faction=7 name_general=NightElf name=Night Elf +classmask=2170 [5] model_m=57 @@ -38,6 +42,7 @@ name_short=Sc faction=1 name_general=Scourge name=Undead +classmask=882 [6] model_m=59 @@ -46,6 +51,7 @@ name_short=Ta faction=1 name_general=Tauren name=Tauren +classmask=2250 [7] model_m=1563 @@ -54,6 +60,7 @@ name_short=Gn faction=7 name_general=Gnome name=Gnome +classmask=850 [8] model_m=1478 @@ -62,6 +69,7 @@ name_short=Tr faction=1 name_general=Troll name=Troll +classmask=506 [9] model_m=6894 @@ -70,6 +78,7 @@ name_short=Go faction=7 name_general=Goblin name=Goblin +classmask=0 [10] model_m=15476 @@ -78,6 +87,7 @@ name_short=Be faction=1 name_general=BloodElf name=Blood Elf +classmask=892 [11] model_m=16125 @@ -86,6 +96,7 @@ name_short=Dr faction=7 name_general=Draenei name=Draenei +classmask=494 [12] model_m=16981 @@ -94,6 +105,7 @@ name_short=Fo faction=7 name_general=FelOrc name=Fel Orc +classmask=0 [13] model_m=17402 @@ -102,6 +114,7 @@ name_short=Na faction=7 name_general=Naga_ name=Naga +classmask=0 [14] model_m=17576 @@ -110,6 +123,7 @@ name_short=Br faction=7 name_general=Broken name=Broken +classmask=0 [15] model_m=17578 @@ -118,6 +132,7 @@ name_short=Sk faction=7 name_general=Skeleton name=Skeleton +classmask=0 [16] model_m=21685 @@ -126,6 +141,7 @@ name_short=Vr faction=7 name_general=Vrykul name=Vrykul +classmask=0 [17] model_m=21780 @@ -134,6 +150,7 @@ name_short=Tu faction=7 name_general=Tuskarr name=Tuskarr +classmask=0 [18] model_m=21963 @@ -142,6 +159,7 @@ name_short=Ft faction=7 name_general=ForestTroll name=Forest Troll +classmask=0 [19] model_m=26316 @@ -150,6 +168,7 @@ name_short=Wt faction=7 name_general=Taunka name=Taunka +classmask=0 [20] model_m=26871 @@ -158,6 +177,7 @@ name_short=NS faction=7 name_general=NorthrendSkeleton name=Northrend Skeleton +classmask=0 [21] model_m=26873 @@ -166,4 +186,5 @@ name_short=It faction=7 name_general=IceTroll name=Ice Troll +classmask=0 diff --git a/src/Client/GUI/CImageLoaderBLP.cpp b/src/Client/GUI/CImageLoaderBLP.cpp index 6cecdde..9ef6826 100644 --- a/src/Client/GUI/CImageLoaderBLP.cpp +++ b/src/Client/GUI/CImageLoaderBLP.cpp @@ -5,12 +5,6 @@ #include "SImage.h" #include "CImageLoaderBLP.h" -#if defined(_DEBUG) && !defined(DEBUG) -#define DEBUG(code) code; -#else -#define DEBUG(code) ; -#endif - namespace irr { namespace video diff --git a/src/Client/GUI/GUIEventReceiver.h b/src/Client/GUI/GUIEventReceiver.h index ab4f462..adee742 100644 --- a/src/Client/GUI/GUIEventReceiver.h +++ b/src/Client/GUI/GUIEventReceiver.h @@ -1,6 +1,8 @@ #ifndef GUIEVENTRECEIVER_H #define GUIEVENTRECEIVER_H +#include + class GUIEventReceiver : public IEventReceiver { @@ -9,30 +11,24 @@ public: { buttons = 0; react_to_keys = true; - memset(&guievent, 0 , sizeof(SEvent)); - memset(&keyevent, 0 , sizeof(SEvent)); - memset(&mouseevent, 0 , sizeof(SEvent)); - guievent_proc = false; - mouseevent_proc = false; - keyevent_proc = false; + store_gui = true; + store_keys = true; + store_mouse = true; } virtual bool OnEvent(const SEvent& event) { // copy all 3 event types into different stores for later external use if(event.EventType == EET_GUI_EVENT) { - guievent = event; - guievent_proc = false; + guieventqueue.push_back(event.GUIEvent); } else if(event.EventType == EET_KEY_INPUT_EVENT) { - keyevent = event; - keyevent_proc = false; + keyeventqueue.push_back(event.KeyInput); } else if(event.EventType == EET_MOUSE_INPUT_EVENT) { - mouseevent = event; - mouseevent_proc = false; + mouseeventqueue.push_back(event.MouseInput); } bool proc = false; @@ -74,13 +70,45 @@ public: return proc; } - bool react_to_keys; + inline bool HasMouseEvent(void) { return mouseeventqueue.size(); } + inline bool HasGUIEvent(void) { return guieventqueue.size(); } + inline bool HasKeyEvent(void) { return keyeventqueue.size(); } + + + inline SEvent::SMouseInput NextMouseEvent(void) + { + ASSERT(HasMouseEvent()) + const SEvent::SMouseInput ev = mouseeventqueue.front(); + mouseeventqueue.pop_front(); + return ev; + } + + inline SEvent::SGUIEvent NextGUIEvent(void) + { + ASSERT(HasGUIEvent()) + SEvent::SGUIEvent ev = guieventqueue.front(); + guieventqueue.pop_front(); + return ev; + } + + inline SEvent::SKeyInput NextKeyEvent(void) + { + ASSERT(HasKeyEvent()) + SEvent::SKeyInput ev = keyeventqueue.front(); + keyeventqueue.pop_front(); + return ev; + } + + bool react_to_keys, store_mouse, store_keys, store_gui; u32 buttons; - SEvent guievent, mouseevent, keyevent; - bool keyevent_proc, mouseevent_proc, guievent_proc; std::map keyToButtonMap; // to simulate button press on key input std::set customHandledEvents; +protected: + std::list guieventqueue; + std::list mouseeventqueue; + std::list keyeventqueue; + }; #endif diff --git a/src/Client/GUI/PseuGUI.cpp b/src/Client/GUI/PseuGUI.cpp index 206a297..b33426b 100644 --- a/src/Client/GUI/PseuGUI.cpp +++ b/src/Client/GUI/PseuGUI.cpp @@ -317,13 +317,11 @@ void PseuGUI::_UpdateSceneState(void) case SCENESTATE_REALMSELECT: _scene = new SceneCharSelection(this); _scene->SetData(ISCENE_CHARSEL_REALMFIRST, 1); - _scene->OnResize(); _scenestate_new = SCENESTATE_CHARSELECT; break; case SCENESTATE_CHARSELECT: _scene = new SceneCharSelection(this); _scene->SetData(ISCENE_CHARSEL_REALMFIRST, 0); - _scene->OnResize(); break; default: _scene = new Scene(this); // will draw nothing, just yield the gui } diff --git a/src/Client/GUI/Scene.h b/src/Client/GUI/Scene.h index db343e2..d619408 100644 --- a/src/Client/GUI/Scene.h +++ b/src/Client/GUI/Scene.h @@ -63,7 +63,7 @@ protected: CCursorController *cursor; SceneState _scenestate; uint32 scenedata[SCENEDATA_SIZE]; // generic storage for anything the PseuInstance thread wants to tell us - SCPDatabase *textdb; + SCPDatabase *textdb, *racedb, *classdb; ZThread::FastMutex mutex; }; @@ -107,6 +107,12 @@ private: IGUIWindow *realmwin; IGUIListBox *realmlistbox; IGUIListBox *charlistbox; // temporary until something better found + //Character creation //temporary. maybe a whole new character creation scene should be used? + IGUIWindow *newcharwin; + IGUIComboBox *raceselect; + IGUIComboBox *classselect; + IGUIEditBox *charname; + std::map racemap, classmap; // maps DB IDs in db to IDs in the combobox, because irrlicht does not allow custom ids in comboboxes }; diff --git a/src/Client/GUI/SceneCharselection.cpp b/src/Client/GUI/SceneCharselection.cpp index 4a2cf2d..e0d6ad0 100644 --- a/src/Client/GUI/SceneCharselection.cpp +++ b/src/Client/GUI/SceneCharselection.cpp @@ -15,141 +15,28 @@ enum GuiElementID BUTTON_SELECT_REALM = 0x10, BUTTON_REALMWIN_OK = 0x20, BUTTON_REALMWIN_CANCEL = 0x40, + BUTTON_NEWCHARWIN_OK = 0x80, + BUTTON_NEWCHARWIN_CANCEL = 0x100, }; SceneCharSelection::SceneCharSelection(PseuGUI *gui) : Scene(gui) { + realmwin = NULL; + newcharwin = NULL; + textdb = instance->dbmgr.GetDB("gui_charselect_text"); + racedb = instance->dbmgr.GetDB("race"); + classdb = instance->dbmgr.GetDB("class"); eventrecv = new GUIEventReceiver(); device->setEventReceiver(eventrecv); - eventrecv->keyToButtonMap[KEY_ESCAPE] = BUTTON_BACK | BUTTON_REALMWIN_CANCEL; - eventrecv->keyToButtonMap[KEY_RETURN] = BUTTON_ENTER_WORLD | BUTTON_REALMWIN_OK; + eventrecv->keyToButtonMap[KEY_ESCAPE] = BUTTON_BACK | BUTTON_REALMWIN_CANCEL | BUTTON_NEWCHARWIN_CANCEL; + eventrecv->keyToButtonMap[KEY_RETURN] = BUTTON_ENTER_WORLD | BUTTON_REALMWIN_OK | BUTTON_NEWCHARWIN_OK; eventrecv->customHandledEvents.insert(EGET_LISTBOX_SELECTED_AGAIN); + eventrecv->store_mouse = false; // do not queue mouse input dimension2d scrn = driver->getScreenSize(); - - OnResize(); // call this manually to draw all buttons and stuff - - if(soundengine) - { - ISoundSource *main_theme = soundengine->getSoundSource("data/misc/main_theme.ogg"); - if(main_theme && !soundengine->isCurrentlyPlaying(main_theme)) - { - soundengine->play2D(main_theme,true); - } - } -} - -void SceneCharSelection::OnUpdate(s32 timepassed) -{ - // treat doubleclick on listboxes as OK button click - if(!eventrecv->guievent_proc) - { - eventrecv->guievent_proc = true; - if(eventrecv->guievent.GUIEvent.EventType == EGET_LISTBOX_SELECTED_AGAIN) - { - if(eventrecv->guievent.GUIEvent.Caller == realmlistbox) - { - eventrecv->buttons |= BUTTON_REALMWIN_OK; - } - else if(eventrecv->guievent.GUIEvent.Caller == charlistbox) - { - eventrecv->buttons |= BUTTON_ENTER_WORLD; - } - } - } - - if(eventrecv->buttons & BUTTON_ENTER_WORLD && !realmwin) - { - logdebug("GUI: SceneCharSelect: Entering world"); - WorldSession *ws = instance->GetWSession(); - if(ws) - { - u32 selected = charlistbox->getSelected(); - if(selected < ws->GetCharsCount()) - { - ws->EnterWorldWithCharacter(ws->GetCharFromList(selected).p._name); - } - else - logerror("Character selection out of bounds! (%u)",selected); - } - else - logerror("GUI: BUTTON_ENTER_ WORLD pressed, but no WorldSession exists!"); - } - if(eventrecv->buttons & BUTTON_BACK && !realmwin) // cant cancel with realmwin open (important for ESC key handling) - { - logdebug("GUI: SceneCharSelect: Back to Loginscreen"); - gui->SetSceneState(SCENESTATE_LOGINSCREEN); - // disconnect from realm server if connected - if(RealmSession *rs = instance->GetRSession()) - rs->SetMustDie(); - if(WorldSession *ws = instance->GetWSession()) - ws->SetMustDie(); - } - if(eventrecv->buttons & BUTTON_DELETE_CHARACTER) - { - guienv->addMessageBox(L"Not yet implemented!", L"Deleting a character does not yet work!"); - } - if(eventrecv->buttons & BUTTON_NEW_CHARACTER) - { - guienv->addMessageBox(L"Not yet implemented!", L"Creating a new character does not yet work!"); - } - if(eventrecv->buttons & BUTTON_SELECT_REALM) - { - if(instance->GetRSession()) - { - scenedata[ISCENE_CHARSEL_REALMFIRST] = 1; // show realm selection window - OnResize(); // force gui redraw to remove window - // TODO: there should exist a better way without full redraw - } - else - { - guienv->addMessageBox(L"Not yet implemented!", L"This action is not yet supported.\nYou can change the realm only while still connected to the realm server."); - } - } - if(eventrecv->buttons & BUTTON_REALMWIN_OK) - { - RealmSession *rs = instance->GetRSession(); - if(rs) - { - u32 selected = realmlistbox->getSelected(); - if(selected < rs->GetRealmCount()) - { - rs->SetRealmAddr(rs->GetRealm(selected).addr_port); - instance->CreateWorldSession(); - eventrecv->buttons |= BUTTON_REALMWIN_CANCEL; // easiest way to close the window without much additional code - } - else - logerror("Realmlist selection out of bounds! (%u)",selected); - } - } - - - // realmlist window - if(eventrecv->buttons & BUTTON_REALMWIN_CANCEL) - { - scenedata[ISCENE_CHARSEL_REALMFIRST] = 0; // do not show realm selection window - OnResize(); // force gui redraw to remove window - // TODO: there should exist a better way without full redraw - } - - eventrecv->buttons = 0; -} - -void SceneCharSelection::OnDelete(void) -{ -} - - -void SceneCharSelection::OnResize(void) -{ - // this seems to be necessary since after a window resize == 0x00000001 for some unknown reason (=CRASH!) - // if anyone knows how to fix that or whats causing it... please do so. - // note: used VC71. also tested it with resizing SceneLogin, there the ptr stays fine. wtf?! - textdb = instance->dbmgr.GetDB("gui_charselect_text"); - - guienv->clear(); // drop all elements and redraw + guienv->addButton(CalcRelativeScreenPos(driver, 0.45f ,0.9f, 0.15f, 0.05f), NULL, BUTTON_ENTER_WORLD, GetStringFromDB(ISCENE_CHARSEL_BUTTONS, DSCENE_CHARSEL_BUTTON_ENTERWORLD).c_str()); guienv->addButton(CalcRelativeScreenPos(driver, 0.9f, 0.92f, 0.08f, 0.03f), NULL, BUTTON_BACK, @@ -160,73 +47,13 @@ void SceneCharSelection::OnResize(void) GetStringFromDB(ISCENE_CHARSEL_BUTTONS, DSCENE_CHARSEL_BUTTON_NEWCHAR).c_str()); guienv->addButton(CalcRelativeScreenPos(driver, 0.78f, 0.92f, 0.1f, 0.03f), NULL, BUTTON_DELETE_CHARACTER, GetStringFromDB(ISCENE_CHARSEL_BUTTONS, DSCENE_CHARSEL_BUTTON_DELCHAR).c_str()); - - realmwin = NULL; - mutex.acquire(); - if(scenedata[ISCENE_CHARSEL_REALMFIRST]) - { - dimension2d dim; - rect pos; - realmwin = guienv->addWindow(CalcRelativeScreenPos(driver, 0.2f, 0.2f, 0.6f, 0.6f), true, - GetStringFromDB(ISCENE_CHARSEL_LABELS, DSCENE_CHARSEL_LABEL_REALMWIN).c_str()); - pos = realmwin->getAbsolutePosition(); // get absolute position and trandform to absolute in-window position - dim.Width = pos.LowerRightCorner.X - pos.UpperLeftCorner.X; - dim.Height = pos.LowerRightCorner.Y - pos.UpperLeftCorner.Y; - realmwin->addChild(guienv->addButton(CalcRelativeScreenPos(dim, 0.7f, 0.93f, 0.12f, 0.05f), realmwin, BUTTON_REALMWIN_OK, - GetStringFromDB(ISCENE_CHARSEL_BUTTONS, DSCENE_CHARSEL_REALMWIN_OK).c_str())); - realmwin->addChild(guienv->addButton(CalcRelativeScreenPos(dim, 0.85f, 0.93f, 0.12f, 0.05f), realmwin, BUTTON_REALMWIN_CANCEL, - GetStringFromDB(ISCENE_CHARSEL_BUTTONS, DSCENE_CHARSEL_REALMWIN_CANCEL).c_str())); - - realmlistbox = guienv->addListBox(CalcRelativeScreenPos(dim, 0.1f, 0.1f, 0.8f, 0.8f), realmwin); - realmwin->addChild(realmlistbox); - - RealmSession *rs = instance->GetRSession(); - - for(uint32 i = 0; i < rs->GetRealmCount(); i++) - { - SRealmInfo& r = rs->GetRealm(i); - core::stringw entry; - entry += r.name.c_str(); - entry += L", "; - switch(r.icon) // icon means here RealmType - { - case 0: entry += "Normal"; break; - case 1: entry += "PvP"; break; - case 4: entry += "Normal(4)"; break; - case 6: entry += "RP"; break; - case 8: entry += "RP-PvP"; break; - case 16: entry += "FFA-PvP"; break; // MaNGOS custom realm type - default: entry += "Unknown"; break; - } - entry += L", ("; - entry += r.chars_here; - entry += L") Chars"; - entry += L" ["; - entry += r.addr_port.c_str(); - entry += L"]"; - realmlistbox->addItem(entry.c_str(), -1); - SColor col; - switch(r.color) - { - case 0: col.set(0xFF, 0x00, 0xFF, 0x00); break; - case 1: col.set(0xFF, 0xFF, 0x00, 0x00); break; - case 2: col.set(0xFF, 0x7F, 0x7F, 0x7F); break; - case 3: col.set(0xFF, 0xB0, 0xB0, 0x00); break; - default: col.set(0xFFFFFFFF); - } - realmlistbox->setItemOverrideColor(i,EGUI_LBC_TEXT,col); - realmlistbox->setItemOverrideColor(i,EGUI_LBC_TEXT_HIGHLIGHT,col); - } - if(realmlistbox->getItemCount()) - realmlistbox->setSelected(0); - } - rect clb_rect = CalcRelativeScreenPos(driver, 0.65f, 0.12f, 0.34f, 0.67f); charlistbox = guienv->addListBox(clb_rect); + + mutex.acquire(); WorldSession *ws = instance->GetWSession(); if(ws) { - SCPDatabase *racedb = instance->dbmgr.GetDB("race"); uint32 ffaction = racedb->GetFieldId("faction"); for(uint32 i = 0; i < ws->GetCharsCount(); i++) { @@ -236,7 +63,7 @@ void SceneCharSelection::OnResize(void) entry += L", "; entry += L"Level "; entry += c.p._level; - entry += "L "; + entry += L" "; entry += c.race.c_str(); entry += L" "; entry += c.class_.c_str(); @@ -262,6 +89,265 @@ void SceneCharSelection::OnResize(void) } } mutex.release(); + + if(soundengine) + { + ISoundSource *main_theme = soundengine->getSoundSource("data/misc/main_theme.ogg"); + if(main_theme && !soundengine->isCurrentlyPlaying(main_theme)) + { + soundengine->play2D(main_theme,true); + } + } +} + +void SceneCharSelection::OnUpdate(s32 timepassed) +{ + // treat doubleclick on listboxes as OK button click + if(eventrecv->HasGUIEvent()) + { + SEvent::SGUIEvent& ev = eventrecv->NextGUIEvent(); + if(ev.EventType == EGET_LISTBOX_SELECTED_AGAIN) + { + if(ev.Caller == realmlistbox) + { + eventrecv->buttons |= BUTTON_REALMWIN_OK; + } + else if(ev.Caller == charlistbox) + { + eventrecv->buttons |= BUTTON_ENTER_WORLD; + } + } + if(ev.EventType == EGET_ELEMENT_CLOSED) + { + if(ev.Caller == realmwin)//realmwin got closed via the close button, remove pointer + { + realmwin = NULL; + } + if(ev.Caller == newcharwin)//got closed via the close button, remove pointer + { + newcharwin = NULL; + } + } + if(ev.EventType == EGET_COMBO_BOX_CHANGED) + { + if(ev.Caller == raceselect) + { + classselect->clear(); + u32 class_name = classdb->GetFieldId("name"); + u32 race_classmask = racedb->GetFieldId("classmask"); + u32 classmask = racedb->GetInt(racemap[raceselect->getSelected()],race_classmask); + for(u32 i=1;i<=classdb->GetRowsCount();i++) + { + if(classmask & 1<GetString(i,class_name); + classmap[classselect->addItem(name.c_str())]=i; + } + } + + + } + } + } + + if(eventrecv->buttons & BUTTON_ENTER_WORLD && !realmwin && !newcharwin) + { + logdebug("GUI: SceneCharSelect: Entering world"); + WorldSession *ws = instance->GetWSession(); + if(ws) + { + u32 selected = charlistbox->getSelected(); + if(selected < ws->GetCharsCount()) + { + ws->EnterWorldWithCharacter(ws->GetCharFromList(selected).p._name); + } + else + logerror("Character selection out of bounds! (%u)",selected); + } + else + logerror("GUI: BUTTON_ENTER_ WORLD pressed, but no WorldSession exists!"); + } + if(eventrecv->buttons & BUTTON_BACK && !realmwin && !newcharwin) // cant cancel with any window open (important for ESC key handling) + { + logdebug("GUI: SceneCharSelect: Back to Loginscreen"); + gui->SetSceneState(SCENESTATE_LOGINSCREEN); + // disconnect from realm server if connected + if(RealmSession *rs = instance->GetRSession()) + rs->SetMustDie(); + if(WorldSession *ws = instance->GetWSession()) + ws->SetMustDie(); + } + + if(eventrecv->buttons & BUTTON_DELETE_CHARACTER) + { + guienv->addMessageBox(L"Not yet implemented!", L"Deleting a character does not yet work!"); + } + if(eventrecv->buttons & BUTTON_NEW_CHARACTER) + { + dimension2d dim; + rect pos; + newcharwin = guienv->addWindow(CalcRelativeScreenPos(driver, 0.2f, 0.2f, 0.6f, 0.6f), true, + GetStringFromDB(ISCENE_CHARSEL_LABELS, DSCENE_CHARSEL_LABEL_NEWCHARWIN).c_str()); + pos = newcharwin->getAbsolutePosition(); // get absolute position and transform to absolute in-window position + dim.Width = pos.LowerRightCorner.X - pos.UpperLeftCorner.X; + dim.Height = pos.LowerRightCorner.Y - pos.UpperLeftCorner.Y; + newcharwin->addChild(guienv->addButton(CalcRelativeScreenPos(dim, 0.7f, 0.93f, 0.12f, 0.05f), newcharwin, BUTTON_NEWCHARWIN_OK, + GetStringFromDB(ISCENE_CHARSEL_BUTTONS, DSCENE_CHARSEL_NEWCHARWIN_OK).c_str())); + newcharwin->addChild(guienv->addButton(CalcRelativeScreenPos(dim, 0.85f, 0.93f, 0.12f, 0.05f), newcharwin, BUTTON_NEWCHARWIN_CANCEL, + GetStringFromDB(ISCENE_CHARSEL_BUTTONS, DSCENE_CHARSEL_NEWCHARWIN_CANCEL).c_str())); + raceselect = guienv->addComboBox(CalcRelativeScreenPos(dim, 0.1f,0.1f,0.8f,0.05f), newcharwin); + u32 race_name = racedb->GetFieldId("name"); + u32 race_classmask = racedb->GetFieldId("classmask"); + for(u32 i=1;i<=racedb->GetRowsCount();i++) + { + if(racedb->GetUint32(i,race_classmask)) //If the race has a classmask, it is playable + { + core::stringw name = racedb->GetString(i,race_name); + racemap[raceselect->addItem(name.c_str())] = i; + } + } + + + newcharwin->addChild(raceselect); + classselect = guienv->addComboBox(CalcRelativeScreenPos(dim, 0.1f,0.2f,0.8f,0.05f), newcharwin); + //newcharwin->addChild(classselect); + guienv->addStaticText(L"Char Name", CalcRelativeScreenPos(dim,0.1f,0.3f,0.8f,0.05f),false,true,newcharwin); + charname = guienv->addEditBox(L"", CalcRelativeScreenPos(dim,0.1f,0.35f,0.8f,0.05f),true, newcharwin); + //guienv->addMessageBox(L"Not yet implemented!", L"Creating a new character does not yet work!"); + } + if(eventrecv->buttons & BUTTON_SELECT_REALM || scenedata[ISCENE_CHARSEL_REALMFIRST]) + { + scenedata[ISCENE_CHARSEL_REALMFIRST] = 0; + if(instance->GetRSession()) + { + dimension2d dim; + rect pos; + realmwin = guienv->addWindow(CalcRelativeScreenPos(driver, 0.2f, 0.2f, 0.6f, 0.6f), true, + GetStringFromDB(ISCENE_CHARSEL_LABELS, DSCENE_CHARSEL_LABEL_REALMWIN).c_str()); + pos = realmwin->getAbsolutePosition(); // get absolute position and transform to absolute in-window position + dim.Width = pos.LowerRightCorner.X - pos.UpperLeftCorner.X; + dim.Height = pos.LowerRightCorner.Y - pos.UpperLeftCorner.Y; + realmwin->addChild(guienv->addButton(CalcRelativeScreenPos(dim, 0.7f, 0.93f, 0.12f, 0.05f), realmwin, BUTTON_REALMWIN_OK, + GetStringFromDB(ISCENE_CHARSEL_BUTTONS, DSCENE_CHARSEL_REALMWIN_OK).c_str())); + realmwin->addChild(guienv->addButton(CalcRelativeScreenPos(dim, 0.85f, 0.93f, 0.12f, 0.05f), realmwin, BUTTON_REALMWIN_CANCEL, + GetStringFromDB(ISCENE_CHARSEL_BUTTONS, DSCENE_CHARSEL_REALMWIN_CANCEL).c_str())); + realmlistbox = guienv->addListBox(CalcRelativeScreenPos(dim, 0.1f, 0.1f, 0.8f, 0.8f), realmwin); + realmwin->addChild(realmlistbox); + mutex.acquire(); + RealmSession *rs = instance->GetRSession(); + + for(uint32 i = 0; i < rs->GetRealmCount(); i++) + { + SRealmInfo& r = rs->GetRealm(i); + core::stringw entry; + entry += r.name.c_str(); + entry += L", "; + switch(r.icon) // icon means here RealmType + { + case 0: entry += "Normal"; break; + case 1: entry += "PvP"; break; + case 4: entry += "Normal(4)"; break; + case 6: entry += "RP"; break; + case 8: entry += "RP-PvP"; break; + case 16: entry += "FFA-PvP"; break; // MaNGOS custom realm type + default: entry += "Unknown"; break; + } + entry += L", ("; + entry += r.chars_here; + entry += L") Chars"; + entry += L" ["; + entry += r.addr_port.c_str(); + entry += L"]"; + realmlistbox->addItem(entry.c_str(), -1); + SColor col; + switch(r.color) + { + case 0: col.set(0xFF, 0x00, 0xFF, 0x00); break; + case 1: col.set(0xFF, 0xFF, 0x00, 0x00); break; + case 2: col.set(0xFF, 0x7F, 0x7F, 0x7F); break; + case 3: col.set(0xFF, 0xB0, 0xB0, 0x00); break; + default: col.set(0xFFFFFFFF); + } + realmlistbox->setItemOverrideColor(i,EGUI_LBC_TEXT,col); + realmlistbox->setItemOverrideColor(i,EGUI_LBC_TEXT_HIGHLIGHT,col); + } + if(realmlistbox->getItemCount()) + realmlistbox->setSelected(0); + mutex.release(); + } + else + { + guienv->addMessageBox(L"Not yet implemented!", L"This action is not yet supported.\nYou can change the realm only while still connected to the realm server."); + } + } + if(eventrecv->buttons & BUTTON_REALMWIN_OK && realmwin) + { + RealmSession *rs = instance->GetRSession(); + if(rs) + { + u32 selected = realmlistbox->getSelected(); + if(selected < rs->GetRealmCount()) + { + rs->SetRealmAddr(rs->GetRealm(selected).addr_port); + instance->CreateWorldSession(); + eventrecv->buttons |= BUTTON_REALMWIN_CANCEL; // easiest way to close the window without much additional code + } + else + logerror("Realmlist selection out of bounds! (%u)",selected); + } + } + + if(eventrecv->buttons & BUTTON_NEWCHARWIN_OK && newcharwin) + { + core::stringc tmp=charname->getText(); + u8 race = racemap[raceselect->getSelected()]; + u8 cclass = classmap[classselect->getSelected()]; + log("Creating character Race %i Class %i Name %s",race,cclass,tmp.c_str()); + if(tmp.size() && race && cclass) + { + WorldSession *ws=instance->GetWSession(); + if(ws) + { + WorldPacket packet(CMSG_CHAR_CREATE,(tmp.size()+1)+1+1+1+1+1+1+1+1+1); + packet<AddSendWorldPacket(packet); + eventrecv->buttons |= BUTTON_NEWCHARWIN_CANCEL; // easiest way to close the window without much additional code + } + else + logerror("Trying to create new Character, but no WorldSession exists."); + } + else + logerror("Race, Class or Name not set!"); + } + + // realmlist window + + if(eventrecv->buttons & BUTTON_REALMWIN_CANCEL && realmwin) + { + realmwin->remove(); + realmwin=NULL; + } + + // new character window + if(eventrecv->buttons & BUTTON_NEWCHARWIN_CANCEL && newcharwin) + { + newcharwin->remove(); + newcharwin=NULL; + } + + eventrecv->buttons = 0; +} + +void SceneCharSelection::OnDelete(void) +{ +} + + +void SceneCharSelection::OnResize(void) +{ +//TODO: Handle Resizes correctly. This goes for the loginscreen as well } diff --git a/src/Client/GUI/SceneData.h b/src/Client/GUI/SceneData.h index 5815a1c..dd5dd57 100644 --- a/src/Client/GUI/SceneData.h +++ b/src/Client/GUI/SceneData.h @@ -62,11 +62,14 @@ enum SceneCharSelectButtons DSCENE_CHARSEL_BUTTON_BACK = 4, DSCENE_CHARSEL_REALMWIN_OK = 5, DSCENE_CHARSEL_REALMWIN_CANCEL = 6, + DSCENE_CHARSEL_NEWCHARWIN_OK = 7, + DSCENE_CHARSEL_NEWCHARWIN_CANCEL = 8, }; enum SceneCharSelectLabels { DSCENE_CHARSEL_LABEL_REALMWIN = 0, + DSCENE_CHARSEL_LABEL_NEWCHARWIN = 1, }; diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp index c910d5c..d0aaa36 100644 --- a/src/Client/World/WorldSession.cpp +++ b/src/Client/World/WorldSession.cpp @@ -577,17 +577,19 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket) PlayerEnum plr[10]; // max characters per realm is 10 uint8 dummy8; uint32 dummy32; - + bool char_found; _charList.clear(); recvPacket >> num; if(num==0) { - logerror("No chars found!"); - GetInstance()->SetError(); - return; + logdetail("No chars found!"); + char_found = false; + //GetInstance()->SetError(); + //return; } - + else + { logdetail("Chars in list: %u",num); _LoadCache(); // we are about to login, so we need cache data // TODO: load cache on loadingscreen @@ -623,7 +625,7 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket) plrNameCache.AddInfo(plr[i]._guid, plr[i]._name); // TODO: set after loadingscreen, after loading cache } - bool char_found=false; + char_found=false; SCPDatabase *zonedb = GetDBMgr().GetDB("zone"), *racedb = GetDBMgr().GetDB("race"), @@ -667,13 +669,14 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket) if(plr[i]._items[inv].displayId) logdebug("-> Has Item: Model=%u InventoryType=%u",plr[i]._items[inv].displayId,plr[i]._items[inv].inventorytype); } - if(plr[i]._name==GetInstance()->GetConf()->charname || num == 1) + if(plr[i]._name==GetInstance()->GetConf()->charname) { charId = i; char_found=true; } } + } if(!char_found) { if(PseuGUI *gui = GetInstance()->GetGUI()) diff --git a/src/tools/stuffextract/DBCFieldData.h b/src/tools/stuffextract/DBCFieldData.h index d2e9de6..8ce8839 100644 --- a/src/tools/stuffextract/DBCFieldData.h +++ b/src/tools/stuffextract/DBCFieldData.h @@ -427,6 +427,16 @@ static const char *GameObjectDisplayInfoFormat = { }; +// GameObjectDisplayInfo + +enum ChrBaseInfoEnum +{ + CBI_RACE = 0, + CBI_CLASS = 1, + CBI_END = 2 +}; + + #endif diff --git a/src/tools/stuffextract/StuffExtract.cpp b/src/tools/stuffextract/StuffExtract.cpp index 29d68fc..0e61343 100644 --- a/src/tools/stuffextract/StuffExtract.cpp +++ b/src/tools/stuffextract/StuffExtract.cpp @@ -187,6 +187,14 @@ std::string AutoGetDataString(DBCFile::Iterator& it, const char* format, uint32 s << (*it).getFloat(field); return s.str(); } + else if(format[field]=='c') + { + if((*it).getUChar(field) == 0 && skip_null) + return ""; // do not explicitly write float fields that are 0 + std::stringstream s; + s << (int)(*it).getUChar(field); + return s.str(); + } else if(format[field]=='s' && (*it).getUInt(field)) { return (*it).getString(field); @@ -254,10 +262,11 @@ void OutMD5(char *path, MD5FileMap& fm) bool ConvertDBC(void) { std::map racemap; // needed to extract other dbc files correctly + std::map classmask; //from CharBaseInfo.dbc SCPStorageMap EmoteDataStorage,RaceDataStorage,SoundDataStorage,MapDataStorage,ZoneDataStorage,ItemDisplayInfoStorage, - CreatureModelStorage,CreatureDisplayInfoStorage,NPCSoundStorage,CharSectionStorage, GameObjectDisplayInfoStorage; // will store the converted data from dbc files + CreatureModelStorage,CreatureDisplayInfoStorage,NPCSoundStorage,CharSectionStorage, GameObjectDisplayInfoStorage, ChrBaseInfoStorage; // will store the converted data from dbc files DBCFile EmotesText,EmotesTextData,EmotesTextSound,ChrRaces,SoundEntries,Map,AreaTable,ItemDisplayInfo, - CreatureModelData,CreatureDisplayInfo,NPCSounds,CharSections,GameObjectDisplayInfo; + CreatureModelData,CreatureDisplayInfo,NPCSounds,CharSections,GameObjectDisplayInfo, ChrBaseInfo; printf("Opening DBC archive...\n"); MPQHelper mpq("dbc"); @@ -275,10 +284,20 @@ bool ConvertDBC(void) GameObjectDisplayInfo.openmem(mpq.ExtractFile("DBFilesClient\\GameObjectDisplayInfo.dbc")); NPCSounds.openmem(mpq.ExtractFile("DBFilesClient\\NPCSounds.dbc")); CharSections.openmem(mpq.ExtractFile("DBFilesClient\\CharSections.dbc")); + ChrBaseInfo.openmem(mpq.ExtractFile("DBFilesClient\\CharBaseInfo.dbc")); //... printf("DBC files opened.\n"); //... - printf("Reading data: races.."); + printf("Reading data: chrbaseinfo.."); + for(DBCFile::Iterator it = ChrBaseInfo.begin(); it != ChrBaseInfo.end(); ++it) + { + uint32 race = (uint32)(*it).getUChar(CBI_RACE); + uint32 cclass = (uint32)(*it).getUChar(CBI_CLASS); + classmask[race] |= 1<(offset+field*4); } + unsigned char getUChar(size_t field) const + { + assert(field < file.fieldCount); + return *reinterpret_cast(offset+field); + } const char *getString(size_t field) const { assert(field < file.fieldCount);