* implemented realm and character selection from the GUI

* added support for map tile sound emitters (MCSE-chunks) (needs more debugging)
* added MasterSoundVolume=0..1 conf option to /conf/gui.conf
* fixed window resize & added related functions to the scenes (OnResize()). TODO: fix SceneLogin resize.
* implemented "Community Site" button functionality on Win32
* misc stuff
* TODO: fix crypt error on realm change.
* moved linux configure.ac script to PseuWoW root dir instead of /src
This commit is contained in:
false_genesis 2008-08-27 23:41:12 +00:00
parent 4ee4f6f5d4
commit d7d36c544e
29 changed files with 865 additions and 316 deletions

View File

@ -8,7 +8,7 @@
// 3: OpenGL
// 4: DirectX 8.1
// 5: DirectX 9.0c
driver=5
driver=3
// resolution and more
resx=1024
@ -28,6 +28,12 @@ depth=32
// 0: No (default)
UseSound=1
// Master Sound Volume. Multiplier that affects all sounds that are played
// 1.0 - max volume
// 0.5 - half sound volume
// 0 - silent
MasterSoundVolume=1.0
//================================================================================================
// Expert options: Renderer finetuning

View File

@ -0,0 +1,14 @@
#dbname=gui_charselect_text
[1]
0=Enter World
1=New Character
2=Delete Character
3=Change Realm
4=Back
5=OK
6=Cancel
[2]
0=Realmlist

View File

@ -23,3 +23,13 @@
0=Oh noes!
1=You have to enter account name and password!
// the text box labels
[3]
0=Account:
1=Password:
// the buttons
[4]
0=Login
1=Quit
2=Community Site

View File

@ -4,10 +4,10 @@ if ?{not ?{IsHooked _startup}}
HookAdd db_loader_load_all
HookEnd
// set up paths; ./data/scp and ./cache are set in the core already
// the SCP files placed in this directory are used to override some values
// in already present SCP files or to add custom fields or content
// note: it DOES matter in which order paths are added!!
// Set up paths; ./data/scp and ./cache are set in the core already.
// The SCP files placed in this directory are used to override some values
// in already present SCP files or to add custom fields or content.
// Note: it DOES matter in which order paths are added!!
AddDBPath ./data/scp-patches
endif
@ -29,11 +29,12 @@ LoadDB creaturemodeldata
LoadDB gameobjectdisplayinfo
// LoadDB itemdisplayinfo // not yet used
// LoadDB charsections // not yet used
// LoadDB sound // not yet used
LoadDB sound
// LoadDB npcsound // not yet used
// GUI related databases
LoadDB gui_login_text
LoadDB gui_charselect_text
log ** Databases loaded.

View File

@ -4,8 +4,8 @@
AC_PREREQ(2.61)
AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
AM_INIT_AUTOMAKE(pseuwow, 0.1)
#AC_CONFIG_SRCDIR([shared/ProgressBar.h])
AM_CONFIG_HEADER([config.h])
#AC_CONFIG_SRCDIR([src/shared/ProgressBar.h])
AM_CONFIG_HEADER([src/config.h])
# Checks for programs.
AC_PROG_CXX
@ -58,18 +58,18 @@ AC_FUNC_UTIME_NULL
AC_FUNC_VPRINTF
AC_CHECK_FUNCS([floor ftime ftruncate getcwd gethostbyaddr gethostbyname gethostname gettimeofday memmove memset mkdir pow realpath select socket sqrt strerror strrchr strstr strtol strtoul uname utime])
#AC_CONFIG_FILES([dep/src/irrlicht/Makefile
# dep/src/zlib/Makefile
# dep/src/zthread/Makefile])
#AC_CONFIG_SUBDIRS([dep/src/irrlicht/jpeglib
# dep/src/irrlicht/libpng])
AC_CONFIG_FILES([Makefile
shared/Makefile
shared/Auth/Makefile
shared/Network/Makefile
Client/Makefile
Client/GUI/Makefile
Client/Realm/Makefile
Client/World/Makefile
Client/DefScript/Makefile])
#AC_CONFIG_FILES([src/dep/src/irrlicht/Makefile
# src/dep/src/zlib/Makefile
# src/dep/src/zthread/Makefile])
#AC_CONFIG_SUBDIRS([src/dep/src/irrlicht/jpeglib
# src/dep/src/irrlicht/libpng])
AC_CONFIG_FILES([src/Makefile
src/shared/Makefile
src/shared/Auth/Makefile
src/shared/Network/Makefile
src/Client/Makefile
src/Client/GUI/Makefile
src/Client/Realm/Makefile
src/Client/World/Makefile
src/Client/DefScript/Makefile])
AC_OUTPUT

View File

@ -1019,6 +1019,18 @@ DefReturnResult DefScriptPackage::SCGui(CmdSet &Set)
{
ins->GetGUI()->SetSceneState(SCENESTATE_LOGINSCREEN);
}
else if(ins->GetRSession() && !ins->GetWSession())
{
ins->GetGUI()->SetSceneState(SCENESTATE_REALMSELECT);
}
else if(ins->GetRSession() && ins->GetWSession())
{
ins->GetGUI()->SetSceneState(SCENESTATE_CHARSELECT);
}
/*else if(ins->GetWSession() && !ins->GetWSession()->InWorld())
{
ins->GetGUI()->SetSceneState(SCENESTATE_LOGINSCREEN);
}*/ // TODO: uncomment after implemented
else if(ins->GetWSession() && ins->GetWSession()->InWorld())
{
ins->GetGUI()->SetSceneState(SCENESTATE_WORLD);

View File

@ -0,0 +1,88 @@
#ifndef GUIEVENTRECEIVER_H
#define GUIEVENTRECEIVER_H
class GUIEventReceiver : public IEventReceiver
{
public:
GUIEventReceiver()
{
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;
}
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;
}
else if(event.EventType == EET_KEY_INPUT_EVENT)
{
keyevent = event;
keyevent_proc = false;
}
else if(event.EventType == EET_MOUSE_INPUT_EVENT)
{
mouseevent = event;
mouseevent_proc = false;
}
bool proc = false;
//GUI EVENT
if (event.EventType == EET_GUI_EVENT)
{
s32 id = event.GUIEvent.Caller->getID();
printf("event type %u ID %u\n",event.GUIEvent.EventType,id);
switch(event.GUIEvent.EventType)
{
case EGET_BUTTON_CLICKED:
buttons += id;
proc = true;
break;
case EGET_MESSAGEBOX_OK: // triggered on enter or ok button click
case EGET_MESSAGEBOX_CANCEL: // triggered on escape
react_to_keys = true; // popup is gone, main window can react to keys again
proc = true;
break;
}
if(customHandledEvents.find(event.GUIEvent.EventType) != customHandledEvents.end())
proc = true;
}
if(react_to_keys && event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
{
std::map<u32,u32>::iterator it = keyToButtonMap.find(event.KeyInput.Key);
if( it != keyToButtonMap.end() )
{
buttons += it->second;
proc = true;
}
}
return proc;
}
bool react_to_keys;
u32 buttons;
SEvent guievent, mouseevent, keyevent;
bool keyevent_proc, mouseevent_proc, guievent_proc;
std::map<u32,u32> keyToButtonMap; // to simulate button press on key input
std::set<u32> customHandledEvents;
};
#endif

View File

@ -121,6 +121,7 @@ void PseuGUI::_Init(void)
_smgr = _device->getSceneManager();
_guienv = _device->getGUIEnvironment();
_timer = _device->getTimer();
_screendimension = _driver->getScreenSize();
//...
// disable crappy irrlicht logging
@ -139,7 +140,14 @@ void PseuGUI::_Init(void)
{
_soundengine = createIrrKlangDevice();
if(_soundengine)
{
logdetail("PseuGUI: Sound Driver: %s",_soundengine->getDriverName());
_soundengine->setSoundVolume(GetInstance()->GetConf()->masterSoundVolume);
// accept only values between 0 and 1
if(_soundengine->getSoundVolume() < 0.0f || _soundengine->getSoundVolume() >= 1.0f)
_soundengine->setSoundVolume(1.0f);
logdetail("PseuGUI: Master Sound Volume: %.3f",_soundengine->getSoundVolume());
}
else
logerror("PseuGUI: Failed to initialize sound engine!");
}
@ -194,7 +202,6 @@ void PseuGUI::Run(void)
_lastpasstime = _passtime;
_passtime = _timer->getTime();
_passtimediff = _passtime - _lastpasstime;
// _HandleWindowResize(); // not yet used; doesnt work
if (!_device->isWindowActive())
{
@ -209,6 +216,18 @@ void PseuGUI::Run(void)
continue;
}
if(_screendimension != _driver->getScreenSize())
{
_scene->OnResize();
_screendimension = _driver->getScreenSize();
}
if(_updateScene)
{
_updateScene = false;
_scene->OnManualUpdate();
}
_scene->OnUpdate(_passtimediff); // custom: process input, set camera, etc
_driver->beginScene(true, true, _scene->GetBackgroundColor()); // irr: call driver to start drawing
_scene->OnDrawBegin(); // custom: draw everything before irrlicht draws everything by itself
@ -295,6 +314,17 @@ void PseuGUI::_UpdateSceneState(void)
case SCENESTATE_GUISTART: _scene = new SceneGuiStart(this); break;
case SCENESTATE_LOGINSCREEN: _scene = new SceneLogin(this); break;
case SCENESTATE_WORLD: _scene = new SceneWorld(this); break;
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
}
_scene->SetState(_scenestate_new);
@ -334,25 +364,3 @@ WorldPosition PseuGUI::GetWorldPosition(void)
return WorldPosition();
}
void PseuGUI::_HandleWindowResize(void)
{
dimension2d<s32> scrn = _driver->getScreenSize();
if(_screendimension.Width != scrn.Width)
{
scrn.Height = s32(scrn.Width * 0.8f); // for now use aspect ratio 5:4
_screendimension = scrn;
_driver->OnResize(scrn);
DEBUG(logdebug("DEBUG: Width resize handled, Height adjusted"));
}
else if(_screendimension.Height != scrn.Height)
{
scrn.Width = s32(scrn.Height * 1.25); // 5:4 here too
_screendimension = scrn;
_driver->OnResize(scrn);
DEBUG(logdebug("DEBUG: Height resize handled, Width adjusted"));
}
// TODO: how to set irrlicht window size ?!
}

View File

@ -17,7 +17,7 @@ enum SceneState
SCENESTATE_NULL = 0,
SCENESTATE_GUISTART,
SCENESTATE_LOGINSCREEN,
SCENESTATE_REALMSELECT,
SCENESTATE_REALMSELECT, // actually both realm and char select will call the same scene, but with slightly different data
SCENESTATE_CHARSELECT,
SCENESTATE_LOADING,
SCENESTATE_WORLD,
@ -73,6 +73,7 @@ class PseuGUI
friend class SceneWorld;
friend class SceneGuiStart;
friend class SceneLogin;
friend class SceneCharSelection;
// ...
public:
@ -103,6 +104,7 @@ public:
void SetSceneState(SceneState);
bool SetSceneData(uint32, uint32);
uint32 GetSceneState(void);
inline void UpdateScene(void) { _updateScene = true; }
// helpers
WorldPosition GetWorldPosition(void);
@ -110,7 +112,6 @@ public:
private:
void _Init(void);
void _UpdateSceneState(void);
void _HandleWindowResize(void);
uint16 _xres,_yres,_colordepth;
bool _windowed,_vsync,_shadows;
bool _initialized,_mustdie;
@ -129,6 +130,7 @@ private:
uint32 _passtime, _lastpasstime, _passtimediff;
irr::core::dimension2d<irr::s32> _screendimension;
uint32 _throttle;//used for frameratelimiting
bool _updateScene; // manually update scene?
};

View File

@ -14,6 +14,7 @@ Scene::Scene(PseuGUI *g)
driver = gui->_driver;
smgr = gui->_smgr;
guienv = gui->_guienv;
rootgui = guienv->getRootGUIElement();
cursor = new CCursorController(device->getCursorControl(), driver);
cursor->setOSCursorVisible(true);
cursor->setVisible(false);
@ -35,6 +36,15 @@ void Scene::OnUpdate(s32)
{
}
void Scene::OnManualUpdate(void)
{
OnResize();
}
void Scene::OnResize(void)
{
}
void Scene::OnDrawBegin(void)
{
}

View File

@ -13,8 +13,24 @@ using namespace gui;
using namespace irrklang;
inline core::rect<s32> CalcRelativeScreenPos(core::dimension2d<s32> dim, f32 x, f32 y, f32 w, f32 h)
{
core::rect<s32> r;
r.UpperLeftCorner.X = dim.Width * x;
r.UpperLeftCorner.Y = dim.Height* y;
r.LowerRightCorner.X = r.UpperLeftCorner.X + (dim.Width * w);
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + (dim.Height * h);
return r;
}
inline core::rect<s32> CalcRelativeScreenPos(video::IVideoDriver* drv, f32 x, f32 y, f32 w, f32 h)
{
return CalcRelativeScreenPos(drv->getScreenSize(),x,y,w,h);
}
class PseuGUI;
class CCursorController;
class GUIEventReceiver;
// base class
class Scene
@ -27,11 +43,14 @@ public:
inline void SetState(SceneState sc) { _scenestate = sc; }
inline SceneState GetState(void) { return _scenestate; }
virtual void OnUpdate(s32);
virtual void OnManualUpdate(void);
virtual void OnDraw(void);
virtual void OnDrawBegin(void);
virtual void OnDelete(void);
virtual void OnResize(void);
virtual video::SColor GetBackgroundColor(void);
virtual void SetData(uint32 index, uint32 value) { scenedata[index] = value; }
protected:
PseuInstance *instance;
PseuGUI *gui;
@ -39,6 +58,7 @@ protected:
irr::video::IVideoDriver* driver;
irr::scene::ISceneManager* smgr;
irr::gui::IGUIEnvironment* guienv;
irr::gui::IGUIElement* rootgui;
irrklang::ISoundEngine *soundengine;
CCursorController *cursor;
SceneState _scenestate;
@ -56,8 +76,6 @@ private:
};
class GUIEventReceiver;
class SceneLogin : public Scene
{
public:
@ -66,14 +84,33 @@ public:
void OnDelete(void);
private:
gui::IGUIElement* root;
IGUIImage *irrlogo, *background;
GUIEventReceiver *eventrecv;
PseuGUI* _gui;
gui::IGUIElement *msgbox;
gui::IGUIWindow *popup;
uint32 msgbox_textid;
};
class CharSelectGUIEventReceiver;
class SceneCharSelection : public Scene
{
public:
SceneCharSelection(PseuGUI *gui);
void OnUpdate(s32);
void OnDelete(void);
void OnResize(void);
private:
GUIEventReceiver *eventrecv;
IGUIWindow *realmwin;
IGUIListBox *realmlistbox;
IGUIListBox *charlistbox; // temporary until something better found
};
class ShTlTerrainSceneNode;
class MCameraFPS;
class MCameraOrbit;
@ -101,7 +138,7 @@ public:
void InitTerrain(void);
void RelocateCamera(void);
void RelocateCameraBehindChar(void);
void UpdateDoodads(void);
void UpdateMapSceneNodes(std::map<uint32,SceneNodeWithGridPos>&);
scene::ISceneNode *GetMyCharacterSceneNode(void);
video::SColor GetBackgroundColor(void);
@ -112,7 +149,6 @@ private:
MCameraFPS *camera;
MyEventReceiver *eventrecv;
ZThread::FastMutex mutex;
PseuGUI *gui;
uint32 map_gridX, map_gridY;
WorldSession *wsession;
World *world;
@ -120,6 +156,7 @@ private:
IGUIStaticText *debugText;
bool debugmode;
std::map<uint32,SceneNodeWithGridPos> _doodads;
std::map<uint32,SceneNodeWithGridPos> _sound_emitters;
scene::ISceneNode *sky;
scene::ISceneNode *selectedNode, *oldSelectedNode, *focusedNode, *oldFocusedNode;
video::SColor envBasicColor;

View File

@ -0,0 +1,259 @@
#include "common.h"
#include "PseuGUI.h"
#include "PseuWoW.h"
#include "Scene.h"
#include "GUIEventReceiver.h"
#include "RealmSession.h"
#include "WorldSession.h"
enum GuiElementID
{
BUTTON_ENTER_WORLD = 0x1,
BUTTON_BACK = 0x2,
BUTTON_NEW_CHARACTER = 0x4,
BUTTON_DELETE_CHARACTER = 0x8,
BUTTON_SELECT_REALM = 0x10,
BUTTON_REALMWIN_OK = 0x20,
BUTTON_REALMWIN_CANCEL = 0x40,
};
SceneCharSelection::SceneCharSelection(PseuGUI *gui) : Scene(gui)
{
textdb = instance->dbmgr.GetDB("gui_charselect_text");
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->customHandledEvents.insert(EGET_LISTBOX_SELECTED_AGAIN);
dimension2d<s32> 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)
{
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.");
}
}
// treat doubleclick on realmlist as OK button click
if(!eventrecv->guievent_proc)
{
eventrecv->guievent_proc = true;
if(eventrecv->guievent.GUIEvent.EventType == EGET_LISTBOX_SELECTED_AGAIN && eventrecv->guievent.GUIEvent.Caller == realmlistbox)
{
eventrecv->buttons |= BUTTON_REALMWIN_OK;
}
//...
}
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 <textdb> == 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,
GetStringFromDB(ISCENE_CHARSEL_BUTTONS, DSCENE_CHARSEL_BUTTON_BACK).c_str());
guienv->addButton(CalcRelativeScreenPos(driver, 0.85f, 0.05f, 0.12f, 0.04f), NULL, BUTTON_SELECT_REALM,
GetStringFromDB(ISCENE_CHARSEL_BUTTONS, DSCENE_CHARSEL_BUTTON_CHANGEREALM).c_str());
guienv->addButton(CalcRelativeScreenPos(driver, 0.85f, 0.8f, 0.1f, 0.04f), NULL, BUTTON_NEW_CHARACTER,
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;
if(scenedata[ISCENE_CHARSEL_REALMFIRST])
{
dimension2d<s32> dim;
rect<s32> 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 <dim> 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<s32> clb_rect = CalcRelativeScreenPos(driver, 0.65f, 0.12f, 0.34f, 0.67f);
charlistbox = guienv->addListBox(clb_rect);
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++)
{
CharacterListExt& c = ws->GetCharFromList(i);
core::stringw entry;
entry += c.p._name.c_str();
entry += L", ";
entry += L"Level ";
entry += c.p._level;
entry += "L ";
entry += c.race.c_str();
entry += L" ";
entry += c.class_.c_str();
entry += L", ";
entry += c.zone.c_str();
entry += L" (";
entry += c.map_.c_str();
entry += L")";
charlistbox->addItem(entry.c_str());
uint32 faction = racedb->GetInt(c.p._race, ffaction);
SColor col;
switch(faction)
{
case 1: col.set(0xFF, 0xFF, 0x30, 0x30); break;
case 7: col.set(0xFF, 0x30, 0x30, 0xFF); break;
default: col.set(0xFFFFFFFF);
}
charlistbox->setItemOverrideColor(i,EGUI_LBC_TEXT,col);
charlistbox->setItemOverrideColor(i,EGUI_LBC_TEXT_HIGHLIGHT,col);
}
}
}

View File

@ -1,7 +1,7 @@
#ifndef SCENEDATA_H
#define SCENEDATA_H
#define SCENEDATA_SIZE 255
#define SCENEDATA_SIZE 256
// I: index, enums should start with 1
// D: data value
@ -10,8 +10,10 @@
enum SceneLoginDataIndexes
{
ISCENE_LOGIN_CONN_STATUS = 1,
ISCENE_LOGIN_MSGBOX_DUMMY = 2,
ISCENE_LOGIN_END = 3
ISCENE_LOGIN_MSGBOX_DUMMY = 2, // text
ISCENE_LOGIN_LABELS = 3, // text
ISCENE_LOGIN_BUTTONS = 4, // text
ISCENE_LOGIN_END
};
enum SceneLoginConnStatus
@ -29,6 +31,44 @@ enum SceneLoginConnStatus
DSCENE_LOGIN_UNK_ERROR = 10,
DSCENE_LOGIN_FILE_TRANSFER = 11,
};
enum SceneLoginLabels
{
DSCENE_LOGIN_LABEL_ACC = 0,
DSCENE_LOGIN_LABEL_PASS = 1,
};
enum SceneLoginButtons
{
DSCENE_LOGIN_BUTTON_LOGIN = 0,
DSCENE_LOGIN_BUTTON_QUIT = 1,
DSCENE_LOGIN_BUTTON_SITE = 2,
};
enum SceneCharSelectDataIndexes
{
ISCENE_CHARSEL_BUTTONS = 1, // text
ISCENE_CHARSEL_LABELS = 2, // text
ISCENE_CHARSEL_REALMFIRST = 255, // flag that is set when connecting to a realm wasnt possible and the realm list must be shown first
ISCENE_CHARSEL_END
};
enum SceneCharSelectButtons
{
DSCENE_CHARSEL_BUTTON_ENTERWORLD = 0,
DSCENE_CHARSEL_BUTTON_NEWCHAR = 1,
DSCENE_CHARSEL_BUTTON_DELCHAR = 2,
DSCENE_CHARSEL_BUTTON_CHANGEREALM = 3,
DSCENE_CHARSEL_BUTTON_BACK = 4,
DSCENE_CHARSEL_REALMWIN_OK = 5,
DSCENE_CHARSEL_REALMWIN_CANCEL = 6,
};
enum SceneCharSelectLabels
{
DSCENE_CHARSEL_LABEL_REALMWIN = 0,
};
#endif

View File

@ -3,6 +3,7 @@
#include "PseuWoW.h"
#include "Scene.h"
#include "RealmSession.h"
#include "GUIEventReceiver.h"
enum GuiElementID
{
@ -13,37 +14,6 @@ enum GuiElementID
BUTTON_LOGON = 0x10,
};
class GUIEventReceiver : public IEventReceiver
{
public:
GUIEventReceiver()
{
buttons=0;
}
virtual bool OnEvent(const SEvent& event)
{
//GUI EVENT
if (event.EventType == EET_GUI_EVENT)
{
s32 id = event.GUIEvent.Caller->getID();
switch(event.GUIEvent.EventType)
{
case EGET_BUTTON_CLICKED:
logdebug("user clicked button %u",id);
buttons+=id;
return true;
break;
}
}
return false;
}
u32 buttons;
};
//TODO: Reposition elements on resize
//the code happens only ones, We need to, in the main loop ( usually while(driver->run()) ) set the
//positions of each gui element based on the current screensize ( gotten with driver->getScreenSize(); )
@ -53,29 +23,39 @@ SceneLogin::SceneLogin(PseuGUI *gui) : Scene(gui)
textdb = instance->dbmgr.GetDB("gui_login_text");
msgbox_textid = 0;
eventrecv = new GUIEventReceiver();
eventrecv->keyToButtonMap[KEY_RETURN] = BUTTON_LOGON;
eventrecv->keyToButtonMap[KEY_ESCAPE] = BUTTON_QUIT;
device->setEventReceiver(eventrecv);
root = guienv->getRootGUIElement();
dimension2d<s32> scrn = driver->getScreenSize();
irrlogo = guienv->addImage(driver->getTexture("data/misc/irrlichtlogo.png"), core::position2d<s32>(5,5),true,root);
background = guienv->addImage(driver->getTexture("data/misc/sky.jpg"), core::position2d<s32>(5,5),true,root);
irrlogo = guienv->addImage(driver->getTexture("data/misc/irrlichtlogo.png"), core::position2d<s32>(5,5),true,rootgui);
background = guienv->addImage(driver->getTexture("data/misc/sky.jpg"), core::position2d<s32>(5,5),true,rootgui);
background->setRelativePosition(rect<s32>(0,0,scrn.Width,scrn.Height));
irrlogo->setScaleImage(true);
guienv->addStaticText(L"Account:",rect<s32>((scrn.Width*0.5f)-90, (scrn.Height*0.3f)-10, (scrn.Width*0.5f)+90, (scrn.Height*0.3f)+10), false, false, 0, 0);
guienv->addStaticText(L"Password:", rect<s32>((scrn.Width*0.5f)-90, (scrn.Height*0.3f)+50, (scrn.Width*0.5f)+90, (scrn.Height*0.3f)+70), false, false, 0, 0);
guienv->addEditBox(L"", rect<s32>((scrn.Width*0.5f)-90, (scrn.Height*0.3f)+10, (scrn.Width*0.5f)+90, (scrn.Height*0.3f)+30), true, 0, 1);
core::stringw accn;
accn += instance->GetConf()->accname.c_str();
guienv->addStaticText(GetStringFromDB(ISCENE_LOGIN_LABELS,DSCENE_LOGIN_LABEL_ACC).c_str(),rect<s32>((scrn.Width*0.5f)-90, (scrn.Height*0.3f)-10, (scrn.Width*0.5f)+90, (scrn.Height*0.3f)+10), false, false, 0, 0);
guienv->addStaticText(GetStringFromDB(ISCENE_LOGIN_LABELS,DSCENE_LOGIN_LABEL_PASS).c_str(), rect<s32>((scrn.Width*0.5f)-90, (scrn.Height*0.3f)+50, (scrn.Width*0.5f)+90, (scrn.Height*0.3f)+70), false, false, 0, 0);
guienv->addEditBox(accn.c_str(), rect<s32>((scrn.Width*0.5f)-90, (scrn.Height*0.3f)+10, (scrn.Width*0.5f)+90, (scrn.Height*0.3f)+30), true, 0, 1);
guienv->addEditBox(L"", rect<s32>((scrn.Width*0.5f)-90, (scrn.Height*0.3f)+70, (scrn.Width*0.5f)+90, (scrn.Height*0.3f)+90), true, 0, 2)->setPasswordBox(true);
guienv->addButton(rect<s32>(scrn.Width-120, scrn.Height-40, scrn.Width-10, scrn.Height-10), 0, 4, L"Quit");
guienv->addButton(rect<s32>(10, scrn.Height-40, 120, scrn.Height-10), 0, 8, L"Community Site");
guienv->addButton(rect<s32>((scrn.Width*0.5f)-60, (scrn.Height*0.3f)+100, (scrn.Width*0.5f)+60, (scrn.Height*0.3f)+130), 0, 16, L"Logon");
guienv->addButton(rect<s32>(scrn.Width-120, scrn.Height-40, scrn.Width-10, scrn.Height-10), 0, 4, GetStringFromDB(ISCENE_LOGIN_BUTTONS,DSCENE_LOGIN_BUTTON_QUIT).c_str());
guienv->addButton(rect<s32>(10, scrn.Height-40, 120, scrn.Height-10), 0, 8, GetStringFromDB(ISCENE_LOGIN_BUTTONS,DSCENE_LOGIN_BUTTON_SITE).c_str());
guienv->addButton(rect<s32>((scrn.Width*0.5f)-60, (scrn.Height*0.3f)+100, (scrn.Width*0.5f)+60, (scrn.Height*0.3f)+130), 0, 16, GetStringFromDB(ISCENE_LOGIN_BUTTONS,DSCENE_LOGIN_BUTTON_LOGIN).c_str());
msgbox = guienv->addStaticText(GetStringFromDB(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_NOT_CONNECTED).c_str(),rect<s32>((scrn.Width*0.5f)-90, (scrn.Height*0.3f)+150, (scrn.Width*0.5f)+90, (scrn.Height*0.3f)+180),true,true);
if(soundengine)
{
soundengine->play2D("data/misc/main_theme.ogg",true);
ISoundSource *main_theme = soundengine->getSoundSource("data/misc/main_theme.ogg");
if(main_theme && !soundengine->isCurrentlyPlaying(main_theme))
{
soundengine->play2D(main_theme,true);
}
}
popup = NULL;
}
void SceneLogin::OnUpdate(s32 timepassed)
@ -92,12 +72,11 @@ void SceneLogin::OnUpdate(s32 timepassed)
}
if(eventrecv->buttons & BUTTON_LOGON)
{
eventrecv->buttons=0;
logdebug("Commencing Logon");
core::stringc tmp;
tmp=root->getElementFromId(TEXTBOX_NAME,true)->getText();
tmp=rootgui->getElementFromId(TEXTBOX_NAME,true)->getText();
std::string accname =tmp.c_str();
tmp=root->getElementFromId(TEXTBOX_PASSWORD,true)->getText();
tmp=rootgui->getElementFromId(TEXTBOX_PASSWORD,true)->getText();
std::string accpass=tmp.c_str();
if(accname.size() && accpass.size())
{
@ -106,14 +85,27 @@ void SceneLogin::OnUpdate(s32 timepassed)
// we can safely override the conf settings
instance->GetConf()->accname = accname;
instance->GetConf()->accpass = accpass;
// ...but do not set the defscript vars; its just not safe
instance->CreateRealmSession();
}
else
{
guienv->addMessageBox(GetStringFromDB(ISCENE_LOGIN_MSGBOX_DUMMY,0).c_str(),
GetStringFromDB(ISCENE_LOGIN_MSGBOX_DUMMY,1).c_str());
popup = guienv->addMessageBox(GetStringFromDB(ISCENE_LOGIN_MSGBOX_DUMMY,0).c_str(),
GetStringFromDB(ISCENE_LOGIN_MSGBOX_DUMMY,1).c_str());
eventrecv->react_to_keys = false; // prevent main window from processing key input; it must be processed by the msgbox's event recv!
// our eventrecv will handle msgbox close event by itself and enable input again.
}
}
if(eventrecv->buttons & BUTTON_COMMUNITY)
{
#if PLATFORM == PLATFORM_WIN32
ShellExecute(NULL, "open", "http://www.mangosclient.org", NULL, NULL, SW_SHOWNORMAL);
#elif PLATFORM == PLATFORM_UNIX
// linux code here
#elif PLATFORM == PLATFORM_APPLE
// mac code here
#endif
}
eventrecv->buttons = 0;
}

View File

@ -14,6 +14,7 @@
#include "CCursorController.h"
#include "MovementMgr.h"
#include "DrawObject.h"
#include "irrKlangSceneNode.h"
// TODO: replace this by conf value
#define MAX_CAM_DISTANCE 70
@ -35,6 +36,11 @@ SceneWorld::SceneWorld(PseuGUI *g) : Scene(g)
_CalcXYMoveVect(mychar->GetO());
old_char_o = mychar->GetO();
if(soundengine)
{
soundengine->stopAllSounds();
}
ILightSceneNode* light = smgr->addLightSceneNode(0, core::vector3df(0,0,0), SColorf(255, 255, 255, 255), 1000.0f);
SLight ldata = light->getLightData();
ldata.AmbientColor = video::SColorf(0.2f,0.2f,0.2f);
@ -369,7 +375,7 @@ void SceneWorld::OnUpdate(s32 timediff)
device->getCursorControl()->setPosition(mouse_pos);
// rotate character if right mouse button pressed.
if(mouse_pressed_right)
if(mouse_pressed_right && !_freeCameraMove)
{
mychar->GetPositionPtr()->o = PI*3/2 - DEG_TO_RAD(camera->getHeading());
// send update to server only if we turned by some amount and not always when we turn
@ -473,6 +479,7 @@ void SceneWorld::OnDelete(void)
{
DEBUG(logdebug("~SceneWorld()"));
_doodads.clear();
_sound_emitters.clear();
gui->domgr.Clear();
delete camera;
delete eventrecv;
@ -543,7 +550,8 @@ void SceneWorld::UpdateTerrain(void)
return;
}
UpdateDoodads(); // drop doodads on maps not loaded anymore. no maptile pointers are dereferenced here, so it can be done before acquiring the mutex
UpdateMapSceneNodes(_doodads); // drop doodads on maps not loaded anymore. no maptile pointers are dereferenced here, so it can be done before acquiring the mutex
UpdateMapSceneNodes(_sound_emitters); // same with sound emitters
mutex.acquire(); // prevent other threads from deleting maptiles
@ -637,6 +645,63 @@ void SceneWorld::UpdateTerrain(void)
}
}
}
// create sound emitters
logdebug("Loading %u sound emitters for tile (%u, %u)", maptile->GetSoundEmitterCount(), tile_real_x, tile_real_y);
uint32 fieldId[10]; // SCP: file1 - file10 (index 0 not used)
char fieldname_t[10];
SCPDatabase *sounddb = gui->GetInstance()->dbmgr.GetDB("sound");
if(sounddb)
{
for(uint32 i = 0; i < 10; i++)
{
sprintf(fieldname_t,"file%u",i + 1); // starts with "file1"
fieldId[i] = sounddb->GetFieldId(fieldname_t);
}
for(uint32 i = 0; i < maptile->GetSoundEmitterCount(); i++)
{
MCSE_chunk *snd = maptile->GetSoundEmitter(i);
if(_sound_emitters.find(snd->soundPointID) == _sound_emitters.end())
{
CIrrKlangSceneNode *snode = new CIrrKlangSceneNode(soundengine, smgr->getRootSceneNode(), smgr, snd->soundPointID);
snode->drop();
snode->setPosition(core::vector3df(-snd->x, snd->z, -snd->y));
snode->getDebugCube()->setPosition(snode->getPosition());
snode->setMinMaxSoundDistance(snd->minDistance,snd->maxDistance);
bool exists = sounddb->GetRowByIndex(snd->soundNameID);
if(exists)
{
for(uint32 s = 0; s < 10; s++)
{
u32 offs = sounddb->GetInt(snd->soundNameID, fieldId[s]);
if(fieldId[s] != SCP_INVALID_INT && offs && offs != SCP_INVALID_INT)
{
std::string fn = "data/sound/";
fn += sounddb->GetString(snd->soundNameID, fieldId[s]);
snode->addSoundFileName(fn.c_str());
}
}
snode->setLoopingStreamMode();
}
core::stringw txt;
txt += (exists ? sounddb->GetString(snd->soundNameID, "name") : "[NA SoundEmitter]");
txt += L" (";
txt += u32(snd->soundNameID);
txt += L")";
snode->getDebugText()->setPosition(snode->getPosition());
snode->getDebugText()->setText(txt.c_str());
SceneNodeWithGridPos gp;
gp.gx = mapmgr->GetGridX() + tilex - 1;
gp.gy = mapmgr->GetGridY() + tiley - 1;
gp.scenenode = snode;
_sound_emitters[snd->soundPointID] = gp;
}
}
}
}
else
{
@ -679,21 +744,21 @@ void SceneWorld::UpdateTerrain(void)
RelocateCameraBehindChar();
}
// drop unneeded doodads from the map
void SceneWorld::UpdateDoodads(void)
// drop unneeded map SceneNodes from the map
void SceneWorld::UpdateMapSceneNodes(std::map<uint32,SceneNodeWithGridPos>& node_map)
{
uint32 s = _doodads.size();
uint32 s = node_map.size();
std::set<uint32> tmp; // temporary storage for all doodad unique ids
// too bad erasing from a map causes pointer invalidation, so first store all unique ids, and then erase
for(std::map<uint32,SceneNodeWithGridPos>::iterator it = _doodads.begin(); it != _doodads.end(); it++ )
for(std::map<uint32,SceneNodeWithGridPos>::iterator it = node_map.begin(); it != node_map.end(); it++ )
if(!mapmgr->GetTile(it->second.gx, it->second.gy))
tmp.insert(it->first);
for(std::set<uint32>::iterator it = tmp.begin(); it != tmp.end(); it++)
{
_doodads[*it].scenenode->remove();
_doodads.erase(*it);
node_map[*it].scenenode->remove();
node_map.erase(*it);
}
logdebug("SceneWorld: Doodads cleaned up, before: %u, after: %u, dropped: %u", s, _doodads.size(), s - _doodads.size());
logdebug("SceneWorld: MapSceneNodes cleaned up, before: %u, after: %u, dropped: %u", s, node_map.size(), s - node_map.size());
}

View File

@ -29,12 +29,17 @@ CIrrKlangSceneNode::CIrrKlangSceneNode(irrklang::ISoundEngine* soundEngine,
if (SoundEngine)
SoundEngine->grab();
cube = mgr->addCubeSceneNode(0.5f);
cube->setMaterialTexture(0,mgr->getVideoDriver()->getTexture("data/misc/square.jpg"));
text = mgr->addTextSceneNode(mgr->getGUIEnvironment()->getBuiltInFont(), L"", video::SColor(0xFF00AF00));
}
CIrrKlangSceneNode::~CIrrKlangSceneNode()
{
stop();
cube->remove();
if (SoundEngine)
SoundEngine->drop();
@ -52,6 +57,9 @@ void CIrrKlangSceneNode::OnRegisterSceneNode()
void CIrrKlangSceneNode::OnAnimate(u32 timeMs)
{
if(!SoundFileNames.size())
return;
ISceneNode::OnAnimate(timeMs);
// play the sound
@ -84,7 +92,8 @@ void CIrrKlangSceneNode::OnAnimate(u32 timeMs)
else
if (!Sound && (!TimeMsDelayFinished || timeMs > TimeMsDelayFinished))
{
// play new sound
// play new sound; select one from the possible files
core::stringc& SoundFileName = SoundFileNames[ rand() % SoundFileNames.size() ];
if (SoundFileName.size())
Sound = SoundEngine->play3D(SoundFileName.c_str(), pos, false, true, true);
@ -105,6 +114,7 @@ void CIrrKlangSceneNode::OnAnimate(u32 timeMs)
{
if (!Sound)
{
core::stringc& SoundFileName = SoundFileNames[ rand() % SoundFileNames.size() ];
if (SoundFileName.size())
Sound = SoundEngine->play3D(SoundFileName.c_str(), pos, true, true, true);
@ -142,6 +152,7 @@ void CIrrKlangSceneNode::OnAnimate(u32 timeMs)
else
{
// start
core::stringc& SoundFileName = SoundFileNames[ rand() % SoundFileNames.size() ];
if (SoundFileName.size())
Sound = SoundEngine->play3D(SoundFileName.c_str(), pos, false, true, true);
@ -234,7 +245,7 @@ void CIrrKlangSceneNode::render()
material.Lighting = false;
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.MaterialTypeParam = 255;
material.TextureLayer[0].Texture = driver->getTexture("textures/editor_defaults/default_sound.png");
material.TextureLayer[0].Texture = driver->getTexture("data/misc/square.jpg");
core::matrix4 mat;
driver->setTransform(video::ETS_WORLD, mat);
@ -256,122 +267,6 @@ const c8* const IrrKlangPlayModeNames[] =
"nothing", "random", "looping", "play_once", 0
};
//! Writes attributes of the scene node.
void CIrrKlangSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
if (!out)
return;
ISceneNode::serializeAttributes(out, options);
const char** soundNames = 0;
if ( SoundEngine && options && ( options->Flags & io::EARWF_FOR_EDITOR ) )
{
// show a list of all loaded sound files in editor
int count = SoundEngine->getSoundSourceCount();
soundNames = new const char*[count+3];
for (int i=0; i<count; ++i)
soundNames[i] = SoundEngine->getSoundSource(i)->getName();
soundNames[count] = "";
soundNames[count+1] = "<select>"; // editor file selector
soundNames[count+2] = 0;
out->addEnum("SoundFileName", SoundFileName.c_str(), soundNames);
delete [] soundNames;
}
else
{
// only store string of sound file if not in editor
out->addString("SoundFileName", SoundFileName.c_str());
}
// add play modes
out->addEnum("PlayMode", PlayMode, IrrKlangPlayModeNames);
out->addFloat("MinDistance", MinDistance);
out->addFloat("MaxDistance", MaxDistance);
// only save the necessary attributes
switch(PlayMode)
{
case EPM_ONCE:
out->addBool("DeleteWhenFinished", DeleteWhenFinished);
break;
case EPM_RANDOM:
out->addInt("MinTimeMsInterval", MinTimeMsInterval);
out->addInt("MaxTimeMsInterval", MaxTimeMsInterval);
break;
}
}
//! Reads attributes of the scene node.
void CIrrKlangSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
if (!in)
return;
ISceneNode::deserializeAttributes(in);
core::stringc oldFileName = SoundFileName;
SoundFileName = in->getAttributeAsString("SoundFileName");
EPlayMode newMode = (EPlayMode)in->getAttributeAsEnumeration("PlayMode", IrrKlangPlayModeNames);
f32 minDistance = in->getAttributeAsFloat("MinDistance");
f32 maxDistance = in->getAttributeAsFloat("MaxDistance");
setMinMaxSoundDistance(minDistance, maxDistance);
DeleteWhenFinished = in->getAttributeAsBool("DeleteWhenFinished");
if (in->existsAttribute("MinTimeMsInterval"))
MinTimeMsInterval = in->getAttributeAsInt("MinTimeMsInterval");
if (in->existsAttribute("MaxTimeMsInterval"))
MaxTimeMsInterval = in->getAttributeAsInt("MaxTimeMsInterval");
if (newMode != PlayMode || oldFileName != SoundFileName)
{
stop();
TimeMsDelayFinished = 0;
PlayMode = newMode;
}
}
//! Creates a clone of this scene node and its children.
ISceneNode* CIrrKlangSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
// this method is only implemented to let irrEdit be able to copy the
// scene node via CTRL+C, it's not necessary
if (!newParent) newParent = Parent;
if (!newManager) newManager = SceneManager;
CIrrKlangSceneNode* nb = new CIrrKlangSceneNode(SoundEngine, newParent, newManager, ID);
nb->cloneMembers(this, newManager);
nb->SoundFileName = SoundFileName;
nb->MinDistance = MinDistance;
nb->Box = Box;
nb->PlayMode = PlayMode;
nb->TimeMsDelayFinished = TimeMsDelayFinished;
nb->DeleteWhenFinished = DeleteWhenFinished;
nb->MaxTimeMsInterval = MaxTimeMsInterval;
nb->MinTimeMsInterval = MinTimeMsInterval;
nb->drop();
return nb;
}
//! Returns type of the scene node
ESCENE_NODE_TYPE CIrrKlangSceneNode::getType() const
{
@ -426,19 +321,17 @@ void CIrrKlangSceneNode::setRandomMode(int minTimeMs, int maxTimeMs)
//! Sets the sound filename to play
void CIrrKlangSceneNode::setSoundFileName(const char* soundFilename)
void CIrrKlangSceneNode::addSoundFileName(const char* soundFilename)
{
if (soundFilename)
SoundFileName = soundFilename;
else
SoundFileName = "";
if (soundFilename && strlen(soundFilename))
SoundFileNames.push_back(soundFilename);
}
//! Gets the sound filename to play
const char* CIrrKlangSceneNode::getSoundFileName() const
const char* CIrrKlangSceneNode::getSoundFileName(u32 id) const
{
return SoundFileName.c_str();
return SoundFileNames.size() < id ? SoundFileNames[id].c_str() : NULL;
}

View File

@ -72,11 +72,11 @@ public:
// Sound parameters
//! Sets the sound filename to play
void setSoundFileName(const char* soundFilename);
//! Adds a sound filename to play
void addSoundFileName(const char* soundFilename);
//! Gets the sound filename to play
const char* getSoundFileName() const;
const char* getSoundFileName(u32 id) const;
//! Sets the minimal and maximal 3D sound distances.
//! Set to negative values if you want to use the default values of the sound engine.
@ -92,9 +92,9 @@ public:
virtual void render();
virtual const core::aabbox3d<f32>& getBoundingBox() const;
virtual ESCENE_NODE_TYPE getType() const;
ISceneNode* clone(ISceneNode* newParent, ISceneManager* newManager);
void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
scene::ISceneNode *getDebugCube(void) { return cube; }
scene::ITextSceneNode *getDebugText(void) { return text; }
protected:
@ -110,7 +110,7 @@ protected:
irrklang::ISoundEngine* SoundEngine;
irrklang::ISound* Sound;
core::stringc SoundFileName;
core::array<core::stringc> SoundFileNames;
f32 MinDistance;
f32 MaxDistance;
@ -120,6 +120,8 @@ protected:
s32 MaxTimeMsInterval;
s32 MinTimeMsInterval;
s32 PlayedCount;
scene::ISceneNode *cube;
scene::ITextSceneNode *text;
};

View File

@ -518,6 +518,7 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v)
fogfar = atof(v.Get("GUI::FOGFAR").c_str());
fognear = atof(v.Get("GUI::FOGNEAR").c_str());
fov = atof(v.Get("GUI::FOV").c_str());
masterSoundVolume = atof(v.Get("GUI::MASTERSOUNDVOLUME").c_str());
log_setloglevel(debug);
}

View File

@ -69,6 +69,9 @@ class PseuInstanceConf
float fognear;
float fov;
// sound related
float masterSoundVolume;
};

View File

@ -41,8 +41,6 @@ enum eAuthResults
REALM_AUTH_PARENTAL_CONTROL=0x0f ///< Access to this account has been blocked by parental controls. Your settings may be changed in your account preferences at <site>
};
#define ChunkSize 2048
struct SRealmHeader
{
uint8 cmd; // OP code = CMD_REALM_LIST
@ -51,19 +49,6 @@ struct SRealmHeader
uint8 count; // quantity of realms
};
struct SRealmInfo
{
uint8 icon; // icon near realm
uint8 locked; // added in 2.0.x
uint8 color; // color of record
std::string name; // Text zero terminated name of Realm
std::string addr_port; // Text zero terminated address of Realm ("ip:port")
float population; // 1.6 -> population value. lower == lower population and vice versa
uint8 chars_here; // number of characters on this server
uint8 timezone; // timezone
uint8 unknown; //
};
struct AuthHandler
{
uint32 cmd;
@ -260,39 +245,47 @@ void RealmSession::_HandleRealmList(ByteBuffer& pkt)
if(count==0)
return;
// alloc space for as many realms as needed
SRealmInfo *realms=new SRealmInfo[count];
_realms.clear();
_realms.resize(count);
// readout realms
for(uint8 i=0;i<count;i++)
{
pkt >> realms[i].icon;
pkt >> realms[i].locked;
pkt >> realms[i].color;
pkt >> realms[i].name;
pkt >> realms[i].addr_port;
pkt >> realms[i].population;
pkt >> realms[i].chars_here;
pkt >> realms[i].timezone;
pkt >> realms[i].unknown;
pkt >> _realms[i].icon;
pkt >> _realms[i].locked;
pkt >> _realms[i].color;
pkt >> _realms[i].name;
pkt >> _realms[i].addr_port;
pkt >> _realms[i].population;
pkt >> _realms[i].chars_here;
pkt >> _realms[i].timezone;
pkt >> _realms[i].unknown;
}
// the rest of the packet is not interesting
for(uint8 i=0;i<count;i++)
for(uint8 i = 0; i < count; i++)
{
if(realms[i].name==GetInstance()->GetConf()->realmname)
if(!stricmp(_realms[i].name.c_str(), GetInstance()->GetConf()->realmname.c_str()))
{
realmAddr=realms[i].addr_port;
realmAddr = _realms[i].addr_port;
}
logcustom(0,LGREEN,"Realm: %s (%s)",realms[i].name.c_str(),realms[i].addr_port.c_str());
logdetail(" [chars:%d][population:%f][timezone:%d]",realms[i].chars_here,realms[i].population,realms[i].timezone);
logcustom(0,LGREEN,"Realm: %s (%s)",_realms[i].name.c_str(),_realms[i].addr_port.c_str());
logdetail(" [chars:%d][population:%f][timezone:%d]",_realms[i].chars_here,_realms[i].population,_realms[i].timezone);
}
delete [] realms;
// now setup where the worldserver is and how to login there
if(realmAddr.empty()){
log("Realm \"%s\" was not found on the realmlist!",GetInstance()->GetConf()->realmname.c_str());
if(realmAddr.empty())
{
if(PseuGUI *gui = GetInstance()->GetGUI())
{
logdebug("RealmSession: GUI exists, switching to realm selection screen");
gui->SetSceneState(SCENESTATE_REALMSELECT); // realm select is a sub-window of character selection
}
else
{
logerror("Realm \"%s\" was not found on the realmlist!",GetInstance()->GetConf()->realmname.c_str());
}
return;
}
@ -300,17 +293,24 @@ void RealmSession::_HandleRealmList(ByteBuffer& pkt)
// -> convert the worldserver port from string to int
// -> write it into the config & set appropriate vars
uint16 colonpos=realmAddr.find(":");
GetInstance()->GetConf()->worldhost=realmAddr.substr(0,colonpos);
GetInstance()->GetConf()->worldport=atoi(realmAddr.substr(colonpos+1,realmAddr.length()-colonpos-1).c_str());
// set vars
GetInstance()->GetScripts()->variables.Set("WORLDHOST",GetInstance()->GetConf()->worldhost);
GetInstance()->GetScripts()->variables.Set("WORLDPORT",DefScriptTools::toString((uint64)(GetInstance()->GetConf()->worldport)));
SetRealmAddr(realmAddr);
// now we have the correct addr/port, time to create the WorldSession
GetInstance()->CreateWorldSession(); // will be done at next PseuInstance::Update()
}
void RealmSession::SetRealmAddr(std::string host)
{
logdebug("SetRealmAddr [%s]", host.c_str());
uint16 colonpos=host.find(":");
ASSERT(colonpos != std::string::npos);
GetInstance()->GetConf()->worldhost=host.substr(0,colonpos);
GetInstance()->GetConf()->worldport=atoi(host.substr(colonpos+1,host.length()-colonpos-1).c_str());
// set vars
GetInstance()->GetScripts()->variables.Set("WORLDHOST",GetInstance()->GetConf()->worldhost);
GetInstance()->GetScripts()->variables.Set("WORLDPORT",DefScriptTools::toString((uint64)(GetInstance()->GetConf()->worldport)));
}
void RealmSession::SetLogonData(void)
{
_accname=GetInstance()->GetConf()->accname;
@ -557,7 +557,7 @@ void RealmSession::_HandleLogonProof(ByteBuffer& pkt)
if(gui)
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS, DSCENE_LOGIN_AUTH_FAILED);
logerror("Wrong password or invalid account information or authentication error");
DieOrReconnect(true);
DieOrReconnect(false);
return;
// cover all other cases. continue only if success.

View File

@ -4,6 +4,19 @@
#include "common.h"
#include "Auth/MD5Hash.h"
struct SRealmInfo
{
uint8 icon; // icon near realm
uint8 locked; // added in 2.0.x
uint8 color; // color of record
std::string name; // Text zero terminated name of Realm
std::string addr_port; // Text zero terminated address of Realm ("ip:port")
float population; // 1.6 -> population value. lower == lower population and vice versa
uint8 chars_here; // number of characters on this server
uint8 timezone; // timezone
uint8 unknown; //
};
struct AuthHandler;
class RealmSocket;
@ -22,6 +35,9 @@ public:
bool MustDie(void);
void SetMustDie(void);
bool SocketGood(void);
void SetRealmAddr(std::string);
inline uint32 GetRealmCount(void) { return _realms.size(); }
inline SRealmInfo& GetRealm(uint32 i) { return _realms[i]; }
private:
@ -48,6 +64,7 @@ private:
uint64 _file_done, _file_size;
ByteBuffer _filebuf;
ByteBuffer _transbuf; // stores parts of unfinished packets
std::vector<SRealmInfo> _realms;
};

View File

@ -142,7 +142,7 @@ uint32 SCPDatabase::GetFieldType(char *entry)
{
std::map<std::string,SCPFieldDef>::iterator it = _fielddefs.find(entry);
if(it != _fielddefs.end())
return _fielddefs[entry].type;
return it->second.type;
return SCP_INVALID_INT;
}
@ -150,7 +150,7 @@ uint32 SCPDatabase::GetFieldId(char *entry)
{
std::map<std::string,SCPFieldDef>::iterator it = _fielddefs.find(entry);
if(it != _fielddefs.end())
return _fielddefs[entry].id;
return it->second.id;
return SCP_INVALID_INT;
}

View File

@ -42,9 +42,18 @@ WorldSession::~WorldSession()
{
if(PseuGUI *gui = GetInstance()->GetGUI())
{
gui->SetSceneState(SCENESTATE_LOGINSCREEN); // kick back to login gui
// if the realm session still exists, the connection to the world server was not successful
// and we need to show realmlist window again
if(_instance->GetRSession())
{
gui->SetSceneState(SCENESTATE_REALMSELECT);
}
else
{
gui->SetSceneState(SCENESTATE_LOGINSCREEN); // kick back to login gui
}
logdebug("~WorldSession(): Waiting until world GUI is deleted");
while(gui->GetSceneState() != SCENESTATE_LOGINSCREEN) // .. and wait until the world gui is really deleted
while(gui->GetSceneState() == SCENESTATE_WORLD) // .. and wait until the world gui is really deleted
GetInstance()->Sleep(1); // (it can cause crash otherwise)
logdebug("~WorldSession(): ... world GUI deleted, continuing to close session");
}
@ -87,10 +96,6 @@ void WorldSession::Start(void)
log("Connecting to '%s' on port %u",GetInstance()->GetConf()->worldhost.c_str(),GetInstance()->GetConf()->worldport);
_socket=new WorldSocket(_sh,this);
_socket->Open(GetInstance()->GetConf()->worldhost,GetInstance()->GetConf()->worldport);
if(GetInstance()->GetRSession())
{
GetInstance()->GetRSession()->SetMustDie(); // realm session is no longer needed
}
_sh.Add(_socket);
// if we cant connect, wait until the socket gives up (after 5 secs)
@ -546,6 +551,8 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
uint8 dummy8;
uint32 dummy32;
_charList.clear();
recvPacket >> num;
if(num==0)
{
@ -556,6 +563,7 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
logdetail("Chars in list: %u",num);
_LoadCache(); // we are about to login, so we need cache data
// TODO: load cache on loadingscreen
for(unsigned int i=0;i<num;i++)
{
recvPacket >> plr[i]._guid;
@ -585,7 +593,8 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
{
recvPacket >> plr[i]._items[inv].displayId >> plr[i]._items[inv].inventorytype >> dummy32;
}
plrNameCache.AddInfo(plr[i]._guid, plr[i]._name);
plrNameCache.AddInfo(plr[i]._guid, plr[i]._name); // TODO: set after loadingscreen, after loading cache
}
bool char_found=false;
@ -607,6 +616,14 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
if(classdb)
classname = classdb->GetString(plr[i]._class, "name");
CharacterListExt cx;
cx.p = plr[i];
cx.class_ = classname;
cx.race = racename;
cx.zone = zonename;
cx.map_ = mapname;
_charList.push_back(cx);
logcustom(0,LGREEN,"## %s (%u) [%s/%s] Map: %s; Zone: %s",
plr[i]._name.c_str(),
plr[i]._level,
@ -623,43 +640,76 @@ 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)
if(plr[i]._name==GetInstance()->GetConf()->charname || num == 1)
{
charId = i;
char_found=true;
_myGUID=plr[i]._guid;
GetInstance()->GetScripts()->variables.Set("@myguid",DefScriptTools::toString(plr[i]._guid));
GetInstance()->GetScripts()->variables.Set("@myrace",DefScriptTools::toString((uint64)plr[i]._race));
}
}
if(!char_found)
{
logerror("Character \"%s\" was not found on char list!", GetInstance()->GetConf()->charname.c_str());
GetInstance()->SetError();
return;
if(PseuGUI *gui = GetInstance()->GetGUI())
{
gui->SetSceneState(SCENESTATE_CHARSELECT);
gui->UpdateScene();
}
else
{
logerror("Character \"%s\" was not found on char list, can't connect!", GetInstance()->GetConf()->charname.c_str());
GetInstance()->SetError();
return;
}
}
else
{
log("Entering World with Character \"%s\"...", plr[charId]._name.c_str());
// create the character and add it to the objmgr.
// note: this is the only object that has to stay in memory unless its explicitly deleted by the server!
// that means even if the server sends create object with that guid, do NOT recreate it!!
MyCharacter *my = new MyCharacter();
my->Create(_myGUID);
my->SetName(plr[charId]._name);
objmgr.Add(my);
// TODO: initialize the world here, and load required maps.
// must remove appropriate code from _HandleLoginVerifyWorldOpcode() then!!
WorldPacket pkt(CMSG_PLAYER_LOGIN,8);
pkt << _myGUID;
SendWorldPacket(pkt);
EnterWorldWithCharacter(plr[charId]._name.c_str());
}
}
void WorldSession::EnterWorldWithCharacter(std::string name)
{
logdebug("EnterWorldWithCharacter(%s)",name.c_str());
_myGUID = 0;
for(CharList::iterator it = _charList.begin(); it != _charList.end(); it++)
{
if(!stricmp(it->p._name.c_str(), name.c_str()))
{
_myGUID = it->p._guid;
GetInstance()->GetScripts()->variables.Set("@myguid",DefScriptTools::toString(_myGUID));
GetInstance()->GetScripts()->variables.Set("@myrace",DefScriptTools::toString(it->p._race));
}
}
if(!_myGUID)
{
logerror("Character '%s' does not exist on this account");
return;
}
log("Entering World with Character \"%s\"...", name.c_str());
// create the character and add it to the objmgr.
// note: this is the only object that has to stay in memory unless its explicitly deleted by the server!
// that means even if the server sends create object with that guid, do NOT recreate it!!
MyCharacter *my = new MyCharacter();
my->Create(_myGUID);
my->SetName(name);
objmgr.Add(my);
// TODO: initialize the world here, and load required maps.
// must remove appropriate code from _HandleLoginVerifyWorldOpcode() then!!
WorldPacket pkt(CMSG_PLAYER_LOGIN,8);
pkt << _myGUID;
SendWorldPacket(pkt);
// close realm session when logging into world
if(!MustDie() && _socket->IsOk() && GetInstance()->GetRSession())
{
GetInstance()->GetRSession()->SetMustDie(); // realm session is no longer needed
}
}
void WorldSession::_HandleSetProficiencyOpcode(WorldPacket& recvPacket)
{

View File

@ -39,7 +39,19 @@ struct DelayedWorldPacket
clock_t when;
};
// helper used for GUI
struct CharacterListExt
{
PlayerEnum p;
std::string zone;
std::string class_;
std::string race;
std::string map_;
};
typedef std::vector<WhoListEntry> WhoList;
typedef std::vector<CharacterListExt> CharList;
typedef std::deque<DelayedWorldPacket> DelayedPacketQueue;
class WorldSession
@ -75,6 +87,10 @@ public:
std::string GetOrRequestPlayerName(uint64);
std::string DumpPacket(WorldPacket& pkt, int errpos = -1, char *errstr = NULL);
inline uint32 GetCharsCount(void) { return _charList.size(); }
inline CharacterListExt& GetCharFromList(uint32 id) { return _charList[id]; }
void EnterWorldWithCharacter(std::string);
// CMSGConstructor
void SendChatMessage(uint32 type, uint32 lang, std::string msg, std::string to="");
@ -160,8 +176,10 @@ private:
uint64 _myGUID;
World *_world;
WhoList _whoList;
CharList _charList;
uint32 _lag_ms;
std::bitset<MAX_OPCODE_ID> _disabledOpcodes;
};
#endif

View File

@ -127,4 +127,5 @@ void WorldSocket::InitCrypt(BigNumber *k)
{
_crypt.SetKey(k);
_crypt.Init();
logdebug("WorldSocket: Crypt initialized");
}

View File

@ -444,6 +444,9 @@
<File
RelativePath=".\Client\Gui\DrawObjMgr.h">
</File>
<File
RelativePath=".\Client\Gui\GUIEventReceiver.h">
</File>
<File
RelativePath=".\Client\Gui\MCamera.h">
</File>
@ -462,6 +465,9 @@
<File
RelativePath=".\Client\Gui\Scene.h">
</File>
<File
RelativePath=".\Client\Gui\SceneCharselection.cpp">
</File>
<File
RelativePath=".\Client\Gui\SceneData.h">
</File>

View File

@ -593,6 +593,10 @@
>
</File>
<File
RelativePath=".\Client\Gui\GUIEventReceiver.h"
>
</File>
<File
RelativePath=".\Client\Gui\DrawObjMgr.h"
>
</File>
@ -617,6 +621,10 @@
>
</File>
<File
RelativePath=".\Client\Gui\SceneCharselection.cpp"
>
</File>
<File
RelativePath=".\Client\Gui\Scene.h"
>
</File>

View File

@ -93,6 +93,9 @@ void MapTile::ImportFromADT(ADTFile *adt)
_doodads.push_back(d);
}
// copy sound emitters
_soundemm = adt->_soundemm;
_xbase = _chunks[0].basex;
_ybase = _chunks[0].basey;
_hbase = _chunks[0].baseheight;

View File

@ -51,6 +51,8 @@ public:
inline float GetBaseHeight(void) { return _hbase; }
inline uint32 GetDoodadCount(void) { return _doodads.size(); }
inline Doodad *GetDoodad(uint32 i) { return &_doodads[i]; }
inline uint32 GetSoundEmitterCount(void) { return _soundemm.size(); }
inline MCSE_chunk *GetSoundEmitter(uint32 i) { return &_soundemm[i]; }
private:
MapChunk _chunks[256]; // 16x16
@ -58,6 +60,7 @@ private:
std::vector<std::string> _wmos;
std::vector<std::string> _models;
std::vector<Doodad> _doodads;
std::vector<MCSE_chunk> _soundemm;
float _xbase,_ybase,_hbase;