Compare commits
120 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9d5a668045 | |||
| 0efb541074 | |||
| 4ae58550b5 | |||
| d82e3a8b79 | |||
| 954213f1ff | |||
| d2bb3575fc | |||
| ca6afb72ad | |||
| 670ab22e96 | |||
| 4d71d4cc40 | |||
| 81b3769188 | |||
| c3c6d42a80 | |||
| 3d8ee25ae7 | |||
| decc77e21c | |||
| 501b1e9814 | |||
| 01502372c9 | |||
| a8c309ec9d | |||
| 41d6314beb | |||
| 74ed93ddc7 | |||
| 18a7143926 | |||
| bd68af5875 | |||
| b8806cc209 | |||
| edcb6f05ce | |||
| cb63c9b07c | |||
| a00ddb3142 | |||
| 3431d323e5 | |||
| 84c4dd0497 | |||
| 3e6a05307e | |||
| c45bda645b | |||
| 1210d2d24f | |||
| 894b53e760 | |||
| 4630b7e403 | |||
| 067bf40be7 | |||
| d8045ae339 | |||
| eff23352aa | |||
| 46df0f17b7 | |||
| ddedc06e47 | |||
| 6a999a8a72 | |||
| 8a97cb8c2c | |||
| e011e6bdc5 | |||
| a106134dd1 | |||
| a538cf73d5 | |||
| b273b4c04a | |||
| 248d142c2b | |||
| 2cc7260552 | |||
| fa4ccb6596 | |||
| 87af4f1a1e | |||
| 18b144fa46 | |||
| e71d0b3a09 | |||
| 9710acad6f | |||
| ca2d4c9217 | |||
| bad6cc2fab | |||
| 95e3ce9a69 | |||
| 5583ba4323 | |||
| a18577665a | |||
| 0bdafe7e15 | |||
| 38f6ced633 | |||
| 65f23bbd1a | |||
| 453a211343 | |||
| 1e8f91a871 | |||
| 2a86a09693 | |||
| bd878e20ce | |||
| 92a02c7f0c | |||
| dacb8df674 | |||
| 7356e8ae77 | |||
| 9b2e78a68e | |||
| be90694234 | |||
| e2757a7628 | |||
| 42662c3f61 | |||
| e752dd7b0f | |||
| 44e24b667e | |||
| de6eb38516 | |||
| 74bf70c44d | |||
| cd06ccc1a5 | |||
| dc40ee64cf | |||
| de1cd8d6a8 | |||
| 1923f90329 | |||
| eeac329c49 | |||
| f13e8479e4 | |||
| cf1008f0d9 | |||
| dfae33cbd1 | |||
| 9f3721247d | |||
| d0b2f8e12f | |||
| 051ed0f14c | |||
| 8ea667a0b5 | |||
| b391dde089 | |||
| be67906218 | |||
| 70d4233a15 | |||
| 31fc5a8fa5 | |||
| 1973cfd061 | |||
| 3322783d95 | |||
| 9895e27d5a | |||
| 877c0f59d3 | |||
| 92eb75af7e | |||
| d815f17442 | |||
| 0344fe0d6d | |||
| a10636e067 | |||
| 4b8f9b4330 | |||
| eb897c81e8 | |||
| 963aca218a | |||
| c6981e6216 | |||
| 8b8ef088d9 | |||
| 6704944105 | |||
| 8e50be24d4 | |||
| f9c19a630d | |||
| 78c04718e0 | |||
| bb592b2436 | |||
| 4b5011a579 | |||
| f3fb5017b3 | |||
| 3a9fdd511b | |||
| 57c6f45c21 | |||
| 8d204dc3c4 | |||
| 9413adcf4a | |||
| 99af76c5b5 | |||
| cc6458daa7 | |||
| 8708cfbee0 | |||
| b67e85e87b | |||
| 33c3143de9 | |||
| 5deb6a9d8e | |||
| 3192524922 | |||
| 2a7a2889c6 |
@@ -20,13 +20,17 @@ The most recent stable build for Windows can be found [here](https://dl.dropboxu
|
|||||||
* [lua 5.2](http://www.lua.org/) - The lua programming language
|
* [lua 5.2](http://www.lua.org/) - The lua programming language
|
||||||
* [SQLite3](http://www.sqlite.org/) - A lightweight SQL database engine
|
* [SQLite3](http://www.sqlite.org/) - A lightweight SQL database engine
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
* [WinRAR](http://www.rarlab.com/) - The best compression tool available IMO; only needed for distribution
|
||||||
|
|
||||||
## Copyright
|
## Copyright
|
||||||
|
|
||||||
(Future versions (to be determined) may be released under a modified version of the [Uplink Developer's License](http://www.introversion.co.uk/uplink/developer/license.html).)
|
(Future versions (to be determined) may be released under a modified version of the [Uplink Developer's License](http://www.introversion.co.uk/uplink/developer/license.html).)
|
||||||
|
|
||||||
The current version of Tortuga is released under the [zlib license](http://en.wikipedia.org/wiki/Zlib_License).
|
The current version of Tortuga is released under the [zlib license](http://en.wikipedia.org/wiki/Zlib_License).
|
||||||
|
|
||||||
Copyright (c) 2013, 2014 Kayne Ruse
|
Copyright (c) 2013-2015 Kayne Ruse
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ void BaseScene::HandleEvents() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef USE_EVENT_JOYSTICK
|
#ifdef USE_EVENT_JOYSTICK
|
||||||
//TODO: joystick/gamepad support
|
//EMPTY
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_EVENT_UNKNOWN
|
#ifdef USE_EVENT_UNKNOWN
|
||||||
@@ -59,7 +59,7 @@ protected:
|
|||||||
virtual void KeyUp(SDL_KeyboardEvent const&) {}
|
virtual void KeyUp(SDL_KeyboardEvent const&) {}
|
||||||
|
|
||||||
#ifdef USE_EVENT_JOYSTICK
|
#ifdef USE_EVENT_JOYSTICK
|
||||||
//TODO: joystick/gamepad support
|
//EMPTY
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_EVENT_UNKNOWN
|
#ifdef USE_EVENT_UNKNOWN
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
#include "main_menu.hpp"
|
#include "main_menu.hpp"
|
||||||
#include "options_menu.hpp"
|
#include "options_menu.hpp"
|
||||||
#include "lobby_menu.hpp"
|
#include "lobby_menu.hpp"
|
||||||
#include "in_world.hpp"
|
#include "world.hpp"
|
||||||
#include "disconnected_screen.hpp"
|
#include "disconnected_screen.hpp"
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
@@ -83,7 +83,6 @@ void ClientApplication::Init(int argc, char* argv[]) {
|
|||||||
//debug output
|
//debug output
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
//TODO: enable/disable these with a switch
|
|
||||||
#define DEBUG_OUTPUT_VAR(x) std::cout << "\t" << #x << ": " << x << std::endl;
|
#define DEBUG_OUTPUT_VAR(x) std::cout << "\t" << #x << ": " << x << std::endl;
|
||||||
|
|
||||||
std::cout << "Internal sizes:" << std::endl;
|
std::cout << "Internal sizes:" << std::endl;
|
||||||
@@ -137,11 +136,17 @@ void ClientApplication::Proc() {
|
|||||||
realTime = Clock::now();
|
realTime = Clock::now();
|
||||||
|
|
||||||
//simulate game time
|
//simulate game time
|
||||||
while (simTime < realTime) {
|
if (simTime < realTime) {
|
||||||
//call each user defined function
|
while (simTime < realTime) {
|
||||||
activeScene->RunFrame();
|
//call each user defined function
|
||||||
//~60 FPS
|
activeScene->RunFrame();
|
||||||
simTime += std::chrono::duration<int, std::milli>(16);
|
//~60 FPS
|
||||||
|
simTime += std::chrono::duration<int, std::milli>(16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//give the machine a break
|
||||||
|
SDL_Delay(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
//draw the game to the screen
|
//draw the game to the screen
|
||||||
@@ -164,6 +169,7 @@ void ClientApplication::Quit() {
|
|||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
void ClientApplication::LoadScene(SceneList sceneIndex) {
|
void ClientApplication::LoadScene(SceneList sceneIndex) {
|
||||||
|
//BUG: #16 Resources are being reloaded between scenes
|
||||||
UnloadScene();
|
UnloadScene();
|
||||||
switch(sceneIndex) {
|
switch(sceneIndex) {
|
||||||
//add scene creation calls here
|
//add scene creation calls here
|
||||||
@@ -180,8 +186,8 @@ void ClientApplication::LoadScene(SceneList sceneIndex) {
|
|||||||
case SceneList::LOBBYMENU:
|
case SceneList::LOBBYMENU:
|
||||||
activeScene = new LobbyMenu(&clientIndex, &accountIndex);
|
activeScene = new LobbyMenu(&clientIndex, &accountIndex);
|
||||||
break;
|
break;
|
||||||
case SceneList::INWORLD:
|
case SceneList::WORLD:
|
||||||
activeScene = new InWorld(&clientIndex, &accountIndex);
|
activeScene = new World(&clientIndex, &accountIndex);
|
||||||
break;
|
break;
|
||||||
case SceneList::DISCONNECTEDSCREEN:
|
case SceneList::DISCONNECTEDSCREEN:
|
||||||
activeScene = new DisconnectedScreen();
|
activeScene = new DisconnectedScreen();
|
||||||
|
|||||||
@@ -21,3 +21,26 @@
|
|||||||
*/
|
*/
|
||||||
#include "base_monster.hpp"
|
#include "base_monster.hpp"
|
||||||
|
|
||||||
|
#include "config_utility.hpp"
|
||||||
|
|
||||||
|
void BaseMonster::CorrectSprite() {
|
||||||
|
//TODO: (9) BaseMonster::CorrectSprite()
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BaseMonster::SetHandle(std::string s) {
|
||||||
|
return handle = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BaseMonster::GetHandle() const {
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BaseMonster::SetAvatar(std::string s) {
|
||||||
|
avatar = s;
|
||||||
|
sprite.LoadSurface(ConfigUtility::GetSingleton()["dir.sprites"] + avatar, 4, 1);
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BaseMonster::GetAvatar() const {
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
@@ -29,8 +29,17 @@ public:
|
|||||||
BaseMonster() = default;
|
BaseMonster() = default;
|
||||||
virtual ~BaseMonster() = default;
|
virtual ~BaseMonster() = default;
|
||||||
|
|
||||||
|
void CorrectSprite();
|
||||||
|
|
||||||
|
std::string SetHandle(std::string s);
|
||||||
|
std::string GetHandle() const;
|
||||||
|
std::string SetAvatar(std::string s);
|
||||||
|
std::string GetAvatar() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//
|
//metadata
|
||||||
|
std::string handle;
|
||||||
|
std::string avatar;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -21,59 +21,15 @@
|
|||||||
*/
|
*/
|
||||||
#include "local_character.hpp"
|
#include "local_character.hpp"
|
||||||
|
|
||||||
bool LocalCharacter::ProcessCollisions(std::list<BoundingBox>& boxList) {
|
#include <iostream>
|
||||||
if (CheckCollisionSimple(boxList, origin + motion)) {
|
|
||||||
Vector2 velocity;
|
|
||||||
velocity.x = CorrectVelocityX(boxList, motion.x);
|
|
||||||
velocity.y = CorrectVelocityY(boxList, motion.y);
|
|
||||||
origin += velocity;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
origin += motion;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LocalCharacter::CheckCollisionSimple(std::list<BoundingBox>& boxList, Vector2 newPos) {
|
bool LocalCharacter::ProcessCollisionGrid(std::list<BoundingBox> boxList) {
|
||||||
for (auto& it : boxList) {
|
for(auto& box : boxList) {
|
||||||
if (it.CheckOverlap(bounds + newPos)) {
|
if (box.CheckOverlap(origin + bounds)) {
|
||||||
|
origin -= motion;
|
||||||
|
motion = {0, 0};
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
double LocalCharacter::CorrectVelocityX(std::list<BoundingBox>& boxList, double velocityX) {
|
|
||||||
double ret = velocityX;
|
|
||||||
for (auto& it : boxList) {
|
|
||||||
if (it.CheckOverlap(bounds + origin + Vector2(velocityX, 0) )) {
|
|
||||||
if (velocityX > 0) {
|
|
||||||
ret = std::min(ret, it.x - (origin.x + bounds.x + bounds.w -1));
|
|
||||||
ret = std::min(ret, 0.0);
|
|
||||||
}
|
|
||||||
else if (velocityX < 0) {
|
|
||||||
ret = std::max(ret, (it.x + it.w) - (origin.x + bounds.x));
|
|
||||||
ret = std::max(ret, 0.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
double LocalCharacter::CorrectVelocityY(std::list<BoundingBox>& boxList, double velocityY) {
|
|
||||||
double ret = velocityY;
|
|
||||||
for (auto& it : boxList) {
|
|
||||||
if (it.CheckOverlap(bounds + origin + Vector2(0, velocityY) )) {
|
|
||||||
if (velocityY > 0) {
|
|
||||||
ret = std::min(ret, it.y - (origin.y + bounds.y + bounds.h -1));
|
|
||||||
ret = std::min(ret, 0.0);
|
|
||||||
}
|
|
||||||
else if (velocityY < 0) {
|
|
||||||
ret = std::max(ret, (it.y + it.h) - (origin.y + bounds.y));
|
|
||||||
ret = std::max(ret, 0.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -33,12 +33,10 @@ public:
|
|||||||
LocalCharacter() = default;
|
LocalCharacter() = default;
|
||||||
virtual ~LocalCharacter() = default;
|
virtual ~LocalCharacter() = default;
|
||||||
|
|
||||||
bool ProcessCollisions(std::list<BoundingBox>& boxList);
|
bool ProcessCollisionGrid(std::list<BoundingBox>);
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
bool CheckCollisionSimple(std::list<BoundingBox>& boxList, Vector2 newPos);
|
//NOTE: NO MEMBERS
|
||||||
double CorrectVelocityX(std::list<BoundingBox>& boxList, double velocityX);
|
|
||||||
double CorrectVelocityY(std::list<BoundingBox>& boxList, double velocityY);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -49,11 +49,11 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
class InWorld : public BaseScene {
|
class World: public BaseScene {
|
||||||
public:
|
public:
|
||||||
//Public access members
|
//Public access members
|
||||||
InWorld(int* const argClientIndex, int* const argAccountIndex);
|
World(int* const argClientIndex, int* const argAccountIndex);
|
||||||
~InWorld();
|
~World();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//Frame loop
|
//Frame loop
|
||||||
@@ -71,35 +71,59 @@ protected:
|
|||||||
void KeyDown(SDL_KeyboardEvent const&);
|
void KeyDown(SDL_KeyboardEvent const&);
|
||||||
void KeyUp(SDL_KeyboardEvent const&);
|
void KeyUp(SDL_KeyboardEvent const&);
|
||||||
|
|
||||||
//Basic connections
|
//handle incoming traffic
|
||||||
void HandlePacket(SerialPacket* const);
|
void HandlePacket(SerialPacket* const);
|
||||||
void HandlePing(ServerPacket* const);
|
|
||||||
void HandlePong(ServerPacket* const);
|
|
||||||
|
|
||||||
//Connection control
|
//heartbeat system
|
||||||
|
void hPing(ServerPacket* const);
|
||||||
|
void hPong(ServerPacket* const);
|
||||||
|
|
||||||
|
void CheckHeartBeat();
|
||||||
|
|
||||||
|
//basic connections
|
||||||
void SendLogoutRequest();
|
void SendLogoutRequest();
|
||||||
void SendDisconnectRequest();
|
void SendDisconnectRequest();
|
||||||
void SendShutdownRequest();
|
void SendAdminDisconnectForced();
|
||||||
|
void SendAdminShutdownRequest();
|
||||||
|
|
||||||
void HandleLogoutResponse(ClientPacket* const);
|
void hLogoutResponse(ClientPacket* const);
|
||||||
void HandleDisconnectResponse(ClientPacket* const);
|
void hDisconnectResponse(ClientPacket* const);
|
||||||
void HandleDisconnectForced(ClientPacket* const);
|
void hAdminDisconnectForced(ClientPacket* const);
|
||||||
|
|
||||||
//map management
|
//map management
|
||||||
void SendRegionRequest(int roomIndex, int x, int y);
|
void SendRegionRequest(int roomIndex, int x, int y);
|
||||||
void HandleRegionContent(RegionPacket* const);
|
void hRegionContent(RegionPacket* const);
|
||||||
void UpdateMap();
|
void UpdateMap();
|
||||||
|
|
||||||
//character management
|
//character management
|
||||||
void HandleCharacterCreate(CharacterPacket* const);
|
void hCharacterUpdate(CharacterPacket* const);
|
||||||
void HandleCharacterDelete(CharacterPacket* const);
|
void hCharacterCreate(CharacterPacket* const);
|
||||||
void HandleCharacterQueryExists(CharacterPacket* const);
|
void hCharacterDelete(CharacterPacket* const);
|
||||||
void HandleCharacterSetRoom(CharacterPacket* const);
|
void hQueryCharacterExists(CharacterPacket* const);
|
||||||
void HandleCharacterSetOrigin(CharacterPacket* const);
|
void hQueryCharacterStats(CharacterPacket* const);
|
||||||
void HandleCharacterSetMotion(CharacterPacket* const);
|
void hQueryCharacterLocation(CharacterPacket* const);
|
||||||
|
void hCharacterMovement(CharacterPacket* const);
|
||||||
|
void hCharacterAttack(CharacterPacket* const);
|
||||||
|
void hCharacterDamage(CharacterPacket* const);
|
||||||
|
|
||||||
//player movement
|
//monster management
|
||||||
void SendLocalCharacterMotion();
|
void hMonsterCreate(MonsterPacket* const);
|
||||||
|
void hMonsterDelete(MonsterPacket* const);
|
||||||
|
void hQueryMonsterExists(MonsterPacket* const);
|
||||||
|
void hQueryMonsterStats(MonsterPacket* const);
|
||||||
|
void hQueryMonsterLocation(MonsterPacket* const);
|
||||||
|
void hMonsterMovement(MonsterPacket* const);
|
||||||
|
void hMonsterAttack(MonsterPacket* const);
|
||||||
|
void hMonsterDamage(MonsterPacket* const);
|
||||||
|
|
||||||
|
//chat
|
||||||
|
void hTextBroadcast(TextPacket* const);
|
||||||
|
void hTextSpeech(TextPacket* const);
|
||||||
|
void hTextWhisper(TextPacket* const);
|
||||||
|
|
||||||
|
//general gameplay
|
||||||
|
void SendLocalCharacterMovement();
|
||||||
|
std::list<BoundingBox> GenerateCollisionGrid(Entity*, int tileWidth, int tileHeight);
|
||||||
|
|
||||||
//indexes
|
//indexes
|
||||||
int& clientIndex;
|
int& clientIndex;
|
||||||
@@ -133,7 +157,7 @@ protected:
|
|||||||
LocalCharacter* localCharacter = nullptr;
|
LocalCharacter* localCharacter = nullptr;
|
||||||
|
|
||||||
//heartbeat
|
//heartbeat
|
||||||
//TODO: Heartbeat needs it's own utility
|
//TODO: (2) Heartbeat needs it's own utility
|
||||||
typedef std::chrono::steady_clock Clock;
|
typedef std::chrono::steady_clock Clock;
|
||||||
Clock::time_point lastBeat = Clock::now();
|
Clock::time_point lastBeat = Clock::now();
|
||||||
int attemptedBeats = 0;
|
int attemptedBeats = 0;
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "world.hpp"
|
||||||
|
|
||||||
|
#include "channels.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//character management
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
//DOCS: preexisting characters will result in query responses
|
||||||
|
//DOCS: new characters will result in create messages
|
||||||
|
//DOCS: this client's character will exist in both (skipped)
|
||||||
|
|
||||||
|
void World::hCharacterUpdate(CharacterPacket* const argPacket) {
|
||||||
|
//TODO: (1) Authentication
|
||||||
|
//NOTE: applies to the local character too
|
||||||
|
|
||||||
|
//check that this character exists
|
||||||
|
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
|
||||||
|
if (characterIt != characterMap.end()) {
|
||||||
|
//update the origin and motion, if there's a difference
|
||||||
|
if (characterIt->second.GetOrigin() != argPacket->origin) {
|
||||||
|
characterIt->second.SetOrigin(argPacket->origin);
|
||||||
|
}
|
||||||
|
if (characterIt->second.GetMotion() != argPacket->motion) {
|
||||||
|
characterIt->second.SetMotion(argPacket->motion);
|
||||||
|
characterIt->second.CorrectSprite(); //only correct the sprite if the motion changes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hCharacterCreate(CharacterPacket* const argPacket) {
|
||||||
|
//prevent double message
|
||||||
|
if (characterMap.find(argPacket->characterIndex) != characterMap.end()) {
|
||||||
|
std::ostringstream msg;
|
||||||
|
msg << "Double character creation event; ";
|
||||||
|
msg << "Index: " << argPacket->characterIndex << "; ";
|
||||||
|
msg << "Handle: " << argPacket->handle;
|
||||||
|
throw(std::runtime_error(msg.str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//implicity create and retrieve the entity
|
||||||
|
BaseCharacter* character = &characterMap[argPacket->characterIndex];
|
||||||
|
|
||||||
|
//fill the character's info
|
||||||
|
character->SetHandle(argPacket->handle);
|
||||||
|
character->SetAvatar(argPacket->avatar);
|
||||||
|
character->SetOwner(argPacket->accountIndex);
|
||||||
|
character->SetOrigin(argPacket->origin);
|
||||||
|
character->SetMotion(argPacket->motion);
|
||||||
|
character->SetBounds(argPacket->bounds);
|
||||||
|
|
||||||
|
character->CorrectSprite();
|
||||||
|
|
||||||
|
//check for this player's character
|
||||||
|
if (character->GetOwner() == accountIndex) {
|
||||||
|
localCharacter = static_cast<LocalCharacter*>(character);
|
||||||
|
|
||||||
|
//focus the camera on this character's sprite
|
||||||
|
camera.marginX = (camera.width / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2);
|
||||||
|
camera.marginY = (camera.height/ 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2);
|
||||||
|
|
||||||
|
//focus on this character's info
|
||||||
|
characterIndex = argPacket->characterIndex;
|
||||||
|
roomIndex = argPacket->roomIndex;
|
||||||
|
|
||||||
|
//query the world state (room)
|
||||||
|
CharacterPacket newPacket;
|
||||||
|
memset(&newPacket, 0, MAX_PACKET_SIZE);
|
||||||
|
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
|
||||||
|
newPacket.roomIndex = roomIndex;
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
newPacket.type = SerialPacketType::QUERY_MONSTER_EXISTS;
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug
|
||||||
|
std::cout << "Character Create, total: " << characterMap.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hCharacterDelete(CharacterPacket* const argPacket) {
|
||||||
|
//ignore if this character doesn't exist
|
||||||
|
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
|
||||||
|
if (characterIt == characterMap.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check for this player's character
|
||||||
|
if ((*characterIt).second.GetOwner() == accountIndex) {
|
||||||
|
localCharacter = nullptr;
|
||||||
|
|
||||||
|
//clear the camera
|
||||||
|
camera.marginX = 0;
|
||||||
|
camera.marginY = 0;
|
||||||
|
|
||||||
|
//clear the room
|
||||||
|
roomIndex = -1;
|
||||||
|
regionPager.UnloadAll();
|
||||||
|
characterMap.clear();
|
||||||
|
monsterMap.clear();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//remove this character
|
||||||
|
characterMap.erase(characterIt);
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug
|
||||||
|
std::cout << "Character Delete, total: " << characterMap.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hQueryCharacterExists(CharacterPacket* const argPacket) {
|
||||||
|
//prevent a double message about this player's character
|
||||||
|
// if (argPacket->accountIndex == accountIndex) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
//ignore characters in a different room (sub-optimal)
|
||||||
|
if (argPacket->roomIndex != roomIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//implicitly construct the character if it doesn't exist
|
||||||
|
BaseCharacter* character = &characterMap[argPacket->characterIndex];
|
||||||
|
|
||||||
|
//set/update the character's info
|
||||||
|
character->SetOrigin(argPacket->origin);
|
||||||
|
character->SetMotion(argPacket->motion);
|
||||||
|
character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT});
|
||||||
|
character->SetHandle(argPacket->handle);
|
||||||
|
character->SetAvatar(argPacket->avatar);
|
||||||
|
character->SetOwner(argPacket->accountIndex);
|
||||||
|
character->CorrectSprite();
|
||||||
|
|
||||||
|
//debug
|
||||||
|
std::cout << "Character Query, total: " << characterMap.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hQueryCharacterStats(CharacterPacket* const argPacket) {
|
||||||
|
//TODO: (9) World::hQueryCharacterStats()
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hQueryCharacterLocation(CharacterPacket* const argPacket) {
|
||||||
|
//TODO: (9) World::hQueryCharacterLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hCharacterMovement(CharacterPacket* const argPacket) {
|
||||||
|
//TODO: (1) Authentication
|
||||||
|
if (argPacket->characterIndex == characterIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check that this character exists
|
||||||
|
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
|
||||||
|
if (characterIt != characterMap.end()) {
|
||||||
|
//set the origin and motion
|
||||||
|
characterIt->second.SetOrigin(argPacket->origin);
|
||||||
|
characterIt->second.SetMotion(argPacket->motion);
|
||||||
|
characterIt->second.CorrectSprite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hCharacterAttack(CharacterPacket* const argPacket) {
|
||||||
|
//TODO: (9) World::hCharacterAttack()
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hCharacterDamage(CharacterPacket* const argPacket) {
|
||||||
|
//TODO: (9) World::hCharacterDamage()
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//player movement & collision
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void World::SendLocalCharacterMovement() {
|
||||||
|
CharacterPacket newPacket;
|
||||||
|
newPacket.type = SerialPacketType::CHARACTER_MOVEMENT;
|
||||||
|
|
||||||
|
newPacket.accountIndex = accountIndex;
|
||||||
|
newPacket.characterIndex = characterIndex;
|
||||||
|
newPacket.roomIndex = roomIndex;
|
||||||
|
newPacket.origin = localCharacter->GetOrigin();
|
||||||
|
newPacket.motion = localCharacter->GetMotion();
|
||||||
|
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<BoundingBox> World::GenerateCollisionGrid(Entity* ptr, int tileWidth, int tileHeight) {
|
||||||
|
//prepare for collisions
|
||||||
|
BoundingBox wallBounds = {0, 0, tileWidth, tileHeight};
|
||||||
|
std::list<BoundingBox> boxList;
|
||||||
|
|
||||||
|
//NOTE: for loops were too dense to work with, so I've just used while loops
|
||||||
|
|
||||||
|
//outer loop
|
||||||
|
wallBounds.x = snapToBase((double)wallBounds.w, ptr->GetOrigin().x);
|
||||||
|
while(wallBounds.x < (ptr->GetOrigin() + ptr->GetBounds()).x + ptr->GetBounds().w) {
|
||||||
|
//inner loop
|
||||||
|
wallBounds.y = snapToBase((double)wallBounds.h, ptr->GetOrigin().y);
|
||||||
|
while(wallBounds.y < (ptr->GetOrigin() + ptr->GetBounds()).y + ptr->GetBounds().h) {
|
||||||
|
//check to see if this tile is solid
|
||||||
|
if (regionPager.GetSolid(wallBounds.x / wallBounds.w, wallBounds.y / wallBounds.h)) {
|
||||||
|
//push onto the box set
|
||||||
|
boxList.push_front(wallBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
//increment
|
||||||
|
wallBounds.y += wallBounds.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
//increment
|
||||||
|
wallBounds.x += wallBounds.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(boxList);
|
||||||
|
}
|
||||||
@@ -19,20 +19,21 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#include "door_data.hpp"
|
#include "world.hpp"
|
||||||
|
|
||||||
std::string DoorData::SetRoomName(std::string s) {
|
//-------------------------
|
||||||
return roomName = s;
|
//chat
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void World::hTextBroadcast(TextPacket* const argPacket) {
|
||||||
|
//TODO: (9) World::hTextBroadcast()
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 DoorData::SetDestPosition(Vector2 v) {
|
void World::hTextSpeech(TextPacket* const argPacket) {
|
||||||
return destPosition = v;
|
//TODO: (9) World::hTextSpeech()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DoorData::GetRoomName() {
|
void World::hTextWhisper(TextPacket* const argPacket) {
|
||||||
return roomName;
|
//TODO: (9) World::hTextWhisper()
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 DoorData::GetDestPosition() {
|
|
||||||
return destPosition;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "world.hpp"
|
||||||
|
|
||||||
|
#include "channels.hpp"
|
||||||
|
#include "ip_operators.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//heartbeat system
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void World::hPing(ServerPacket* const argPacket) {
|
||||||
|
ServerPacket newPacket;
|
||||||
|
newPacket.type = SerialPacketType::PONG;
|
||||||
|
network.SendTo(argPacket->srcAddress, &newPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hPong(ServerPacket* const argPacket) {
|
||||||
|
if (*network.GetIPAddress(Channels::SERVER) != argPacket->srcAddress) {
|
||||||
|
throw(std::runtime_error("Heartbeat message received from an unknown source"));
|
||||||
|
}
|
||||||
|
attemptedBeats = 0;
|
||||||
|
lastBeat = Clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::CheckHeartBeat() {
|
||||||
|
//check the connection (heartbeat)
|
||||||
|
if (Clock::now() - lastBeat > std::chrono::seconds(3)) {
|
||||||
|
if (attemptedBeats > 2) {
|
||||||
|
//escape to the disconnect screen
|
||||||
|
SendDisconnectRequest();
|
||||||
|
SetNextScene(SceneList::DISCONNECTEDSCREEN);
|
||||||
|
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "Error: Lost connection to the server";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ServerPacket newPacket;
|
||||||
|
newPacket.type = SerialPacketType::PING;
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
|
||||||
|
attemptedBeats++;
|
||||||
|
lastBeat = Clock::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Connection control
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void World::SendLogoutRequest() {
|
||||||
|
ClientPacket newPacket;
|
||||||
|
|
||||||
|
//send a logout request
|
||||||
|
newPacket.type = SerialPacketType::LOGOUT_REQUEST;
|
||||||
|
newPacket.accountIndex = accountIndex;
|
||||||
|
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::SendDisconnectRequest() {
|
||||||
|
ClientPacket newPacket;
|
||||||
|
|
||||||
|
//send a disconnect request
|
||||||
|
newPacket.type = SerialPacketType::DISCONNECT_REQUEST;
|
||||||
|
newPacket.clientIndex = clientIndex;
|
||||||
|
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::SendAdminDisconnectForced() {
|
||||||
|
//TODO: (9) World::SendAdminDisconnectForced()
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::SendAdminShutdownRequest() {
|
||||||
|
ClientPacket newPacket;
|
||||||
|
|
||||||
|
//send a shutdown request
|
||||||
|
newPacket.type = SerialPacketType::ADMIN_SHUTDOWN_REQUEST;
|
||||||
|
newPacket.accountIndex = accountIndex;
|
||||||
|
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hLogoutResponse(ClientPacket* const argPacket) {
|
||||||
|
if (localCharacter) {
|
||||||
|
characterMap.erase(characterIndex);
|
||||||
|
localCharacter = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
accountIndex = -1;
|
||||||
|
characterIndex = -1;
|
||||||
|
|
||||||
|
//reset the camera
|
||||||
|
camera.marginX = camera.marginY = 0;
|
||||||
|
|
||||||
|
//because, why not? I guess...
|
||||||
|
SendDisconnectRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hDisconnectResponse(ClientPacket* const argPacket) {
|
||||||
|
hLogoutResponse(argPacket);//shortcut
|
||||||
|
SetNextScene(SceneList::DISCONNECTEDSCREEN);
|
||||||
|
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have successfully logged out";
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hAdminDisconnectForced(ClientPacket* const argPacket) {
|
||||||
|
hDisconnectResponse(argPacket);//shortcut
|
||||||
|
SetNextScene(SceneList::DISCONNECTEDSCREEN);
|
||||||
|
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have been forcibly disconnected by the server";
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,414 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "world.hpp"
|
||||||
|
|
||||||
|
#include "channels.hpp"
|
||||||
|
|
||||||
|
#include "terminal_error.hpp"
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Public access members
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
World::World(int* const argClientIndex, int* const argAccountIndex):
|
||||||
|
clientIndex(*argClientIndex),
|
||||||
|
accountIndex(*argAccountIndex)
|
||||||
|
{
|
||||||
|
//setup the utility objects
|
||||||
|
buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp");
|
||||||
|
buttonImage.SetClipH(buttonImage.GetClipH()/3);
|
||||||
|
font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp");
|
||||||
|
|
||||||
|
//pass the utility objects
|
||||||
|
disconnectButton.SetImage(&buttonImage);
|
||||||
|
disconnectButton.SetFont(&font);
|
||||||
|
shutDownButton.SetImage(&buttonImage);
|
||||||
|
shutDownButton.SetFont(&font);
|
||||||
|
|
||||||
|
//set the button positions
|
||||||
|
disconnectButton.SetX(50);
|
||||||
|
disconnectButton.SetY(50 + buttonImage.GetClipH() * 0);
|
||||||
|
shutDownButton.SetX(50);
|
||||||
|
shutDownButton.SetY(50 + buttonImage.GetClipH() * 1);
|
||||||
|
|
||||||
|
//set the button texts
|
||||||
|
disconnectButton.SetText("Disconnect");
|
||||||
|
shutDownButton.SetText("Shut Down");
|
||||||
|
|
||||||
|
//load the tilesheet
|
||||||
|
//TODO: (2) Tile size and tile sheet should be loaded elsewhere
|
||||||
|
tileSheet.Load(config["dir.tilesets"] + "overworld.bmp", 32, 32);
|
||||||
|
|
||||||
|
//Send the character data
|
||||||
|
CharacterPacket newPacket;
|
||||||
|
newPacket.type = SerialPacketType::CHARACTER_LOAD;
|
||||||
|
strncpy(newPacket.handle, config["client.handle"].c_str(), PACKET_STRING_SIZE);
|
||||||
|
strncpy(newPacket.avatar, config["client.avatar"].c_str(), PACKET_STRING_SIZE);
|
||||||
|
newPacket.accountIndex = accountIndex;
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
|
||||||
|
//set the camera's values
|
||||||
|
camera.width = GetScreen()->w;
|
||||||
|
camera.height = GetScreen()->h;
|
||||||
|
|
||||||
|
//debug
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
World::~World() {
|
||||||
|
//unload the local data
|
||||||
|
characterMap.clear();
|
||||||
|
monsterMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Frame loop
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void World::FrameStart() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::Update() {
|
||||||
|
//create and zero the buffer
|
||||||
|
SerialPacket* packetBuffer = reinterpret_cast<SerialPacket*>(new char[MAX_PACKET_SIZE]);
|
||||||
|
memset(packetBuffer, 0, MAX_PACKET_SIZE);
|
||||||
|
|
||||||
|
try {
|
||||||
|
//suck in and process all waiting packets
|
||||||
|
while(network.Receive(packetBuffer)) {
|
||||||
|
HandlePacket(packetBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(terminal_error& e) {
|
||||||
|
throw(e);
|
||||||
|
}
|
||||||
|
catch(std::exception& e) {
|
||||||
|
std::cerr << "HandlePacket Error: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free the buffer
|
||||||
|
delete reinterpret_cast<char*>(packetBuffer);
|
||||||
|
|
||||||
|
//heartbeat system
|
||||||
|
CheckHeartBeat();
|
||||||
|
|
||||||
|
//update all entities
|
||||||
|
for (auto& it : characterMap) {
|
||||||
|
it.second.Update();
|
||||||
|
}
|
||||||
|
for (auto& it : monsterMap) {
|
||||||
|
it.second.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
//update the map
|
||||||
|
UpdateMap();
|
||||||
|
|
||||||
|
//skip the rest without a local character
|
||||||
|
if (!localCharacter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the collidable boxes
|
||||||
|
std::list<BoundingBox> boxList = GenerateCollisionGrid(localCharacter, tileSheet.GetTileW(), tileSheet.GetTileH());
|
||||||
|
|
||||||
|
//process the collisions
|
||||||
|
if (localCharacter->ProcessCollisionGrid(boxList)) {
|
||||||
|
localCharacter->CorrectSprite();
|
||||||
|
SendLocalCharacterMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
//update the camera
|
||||||
|
camera.x = localCharacter->GetOrigin().x - camera.marginX;
|
||||||
|
camera.y = localCharacter->GetOrigin().y - camera.marginY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::FrameEnd() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::RenderFrame() {
|
||||||
|
// SDL_FillRect(GetScreen(), 0, 0);
|
||||||
|
Render(GetScreen());
|
||||||
|
SDL_Flip(GetScreen());
|
||||||
|
fps.Calculate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::Render(SDL_Surface* const screen) {
|
||||||
|
//draw the map
|
||||||
|
for (std::list<Region>::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
|
||||||
|
tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//draw the entities
|
||||||
|
for (auto& it : characterMap) {
|
||||||
|
//BUG: #29 Characters (and other entities) are drawn out of order
|
||||||
|
it.second.DrawTo(screen, camera.x, camera.y);
|
||||||
|
}
|
||||||
|
for (auto& it : monsterMap) {
|
||||||
|
it.second.DrawTo(screen, camera.x, camera.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//draw UI
|
||||||
|
disconnectButton.DrawTo(screen);
|
||||||
|
shutDownButton.DrawTo(screen);
|
||||||
|
std::ostringstream msg;
|
||||||
|
msg << fps.GetFrameRate();
|
||||||
|
font.DrawStringTo(msg.str(), screen, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Event handlers
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void World::QuitEvent() {
|
||||||
|
//two-step logout
|
||||||
|
SendDisconnectRequest();
|
||||||
|
SetNextScene(SceneList::QUIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::MouseMotion(SDL_MouseMotionEvent const& motion) {
|
||||||
|
disconnectButton.MouseMotion(motion);
|
||||||
|
shutDownButton.MouseMotion(motion);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::MouseButtonDown(SDL_MouseButtonEvent const& button) {
|
||||||
|
disconnectButton.MouseButtonDown(button);
|
||||||
|
shutDownButton.MouseButtonDown(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::MouseButtonUp(SDL_MouseButtonEvent const& button) {
|
||||||
|
if (disconnectButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) {
|
||||||
|
SendLogoutRequest();
|
||||||
|
}
|
||||||
|
if (shutDownButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) {
|
||||||
|
SendAdminShutdownRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::KeyDown(SDL_KeyboardEvent const& key) {
|
||||||
|
//hotkeys
|
||||||
|
switch(key.keysym.sym) {
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
//TODO: (3) the escape key should actually control menus and stuff
|
||||||
|
SendLogoutRequest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//character movement
|
||||||
|
if (!localCharacter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vector2 motion = localCharacter->GetMotion();
|
||||||
|
switch(key.keysym.sym) {
|
||||||
|
case SDLK_w:
|
||||||
|
motion.y -= CHARACTER_WALKING_SPEED;
|
||||||
|
break;
|
||||||
|
case SDLK_a:
|
||||||
|
motion.x -= CHARACTER_WALKING_SPEED;
|
||||||
|
break;
|
||||||
|
case SDLK_s:
|
||||||
|
motion.y += CHARACTER_WALKING_SPEED;
|
||||||
|
break;
|
||||||
|
case SDLK_d:
|
||||||
|
motion.x += CHARACTER_WALKING_SPEED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//DOCS: prevents wrong keys screwing with character movement
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//handle diagonals
|
||||||
|
if (motion.x != 0 && motion.y != 0) {
|
||||||
|
motion *= CHARACTER_WALKING_MOD;
|
||||||
|
}
|
||||||
|
//set the info
|
||||||
|
localCharacter->SetMotion(motion);
|
||||||
|
localCharacter->CorrectSprite();
|
||||||
|
SendLocalCharacterMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::KeyUp(SDL_KeyboardEvent const& key) {
|
||||||
|
//character movement
|
||||||
|
if (!localCharacter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vector2 motion = localCharacter->GetMotion();
|
||||||
|
switch(key.keysym.sym) {
|
||||||
|
case SDLK_w:
|
||||||
|
motion.y = std::min(0.0, motion.y += CHARACTER_WALKING_SPEED);
|
||||||
|
break;
|
||||||
|
case SDLK_a:
|
||||||
|
motion.x = std::min(0.0, motion.x += CHARACTER_WALKING_SPEED);
|
||||||
|
break;
|
||||||
|
case SDLK_s:
|
||||||
|
motion.y = std::max(0.0, motion.y -= CHARACTER_WALKING_SPEED);
|
||||||
|
break;
|
||||||
|
case SDLK_d:
|
||||||
|
motion.x = std::max(0.0, motion.x -= CHARACTER_WALKING_SPEED);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//DOCS: prevents wrong keys screwing with character movement
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//BUGFIX: reset cardinal direction speed on key release
|
||||||
|
if (motion.x > 0) {
|
||||||
|
motion.x = CHARACTER_WALKING_SPEED;
|
||||||
|
}
|
||||||
|
else if (motion.x < 0) {
|
||||||
|
motion.x = -CHARACTER_WALKING_SPEED;
|
||||||
|
}
|
||||||
|
if (motion.y > 0) {
|
||||||
|
motion.y = CHARACTER_WALKING_SPEED;
|
||||||
|
}
|
||||||
|
else if (motion.y < 0) {
|
||||||
|
motion.y = -CHARACTER_WALKING_SPEED;
|
||||||
|
}
|
||||||
|
//handle diagonals
|
||||||
|
if (motion.x != 0 && motion.y != 0) {
|
||||||
|
motion *= CHARACTER_WALKING_MOD;
|
||||||
|
}
|
||||||
|
//set the info
|
||||||
|
localCharacter->SetMotion(motion);
|
||||||
|
localCharacter->CorrectSprite();
|
||||||
|
SendLocalCharacterMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Direct incoming traffic
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void World::HandlePacket(SerialPacket* const argPacket) {
|
||||||
|
switch(argPacket->type) {
|
||||||
|
//heartbeat system
|
||||||
|
case SerialPacketType::PING:
|
||||||
|
hPing(static_cast<ServerPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::PONG:
|
||||||
|
hPong(static_cast<ServerPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//game server connections
|
||||||
|
case SerialPacketType::LOGOUT_RESPONSE:
|
||||||
|
hLogoutResponse(static_cast<ClientPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::DISCONNECT_RESPONSE:
|
||||||
|
hDisconnectResponse(static_cast<ClientPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::ADMIN_DISCONNECT_FORCED:
|
||||||
|
hAdminDisconnectForced(static_cast<ClientPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//map management
|
||||||
|
case SerialPacketType::REGION_CONTENT:
|
||||||
|
hRegionContent(static_cast<RegionPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//character management
|
||||||
|
case SerialPacketType::CHARACTER_UPDATE:
|
||||||
|
hCharacterUpdate(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::CHARACTER_CREATE:
|
||||||
|
hCharacterCreate(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::CHARACTER_DELETE:
|
||||||
|
hCharacterDelete(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::QUERY_CHARACTER_EXISTS:
|
||||||
|
hQueryCharacterExists(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::QUERY_CHARACTER_STATS:
|
||||||
|
hQueryCharacterStats(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::QUERY_CHARACTER_LOCATION:
|
||||||
|
hQueryCharacterLocation(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::CHARACTER_MOVEMENT:
|
||||||
|
hCharacterMovement(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::CHARACTER_ATTACK:
|
||||||
|
hCharacterAttack(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::CHARACTER_DAMAGE:
|
||||||
|
hCharacterDamage(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//monster management
|
||||||
|
case SerialPacketType::MONSTER_CREATE:
|
||||||
|
hMonsterCreate(static_cast<MonsterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::MONSTER_DELETE:
|
||||||
|
hMonsterDelete(static_cast<MonsterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::QUERY_MONSTER_EXISTS:
|
||||||
|
hQueryMonsterExists(static_cast<MonsterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::QUERY_MONSTER_STATS:
|
||||||
|
hQueryMonsterStats(static_cast<MonsterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::QUERY_MONSTER_LOCATION:
|
||||||
|
hQueryMonsterLocation(static_cast<MonsterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::MONSTER_MOVEMENT:
|
||||||
|
hMonsterMovement(static_cast<MonsterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::MONSTER_ATTACK:
|
||||||
|
hMonsterAttack(static_cast<MonsterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::MONSTER_DAMAGE:
|
||||||
|
hMonsterDamage(static_cast<MonsterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//chat
|
||||||
|
case SerialPacketType::TEXT_BROADCAST:
|
||||||
|
hTextBroadcast(static_cast<TextPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::TEXT_SPEECH:
|
||||||
|
hTextSpeech(static_cast<TextPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::TEXT_WHISPER:
|
||||||
|
hTextWhisper(static_cast<TextPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//general rejection messages
|
||||||
|
case SerialPacketType::REGION_REJECTION:
|
||||||
|
case SerialPacketType::CHARACTER_REJECTION:
|
||||||
|
case SerialPacketType::QUERY_REJECTION:
|
||||||
|
throw(terminal_error(static_cast<TextPacket*>(argPacket)->text));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::SHUTDOWN_REJECTION:
|
||||||
|
throw(std::runtime_error(static_cast<TextPacket*>(argPacket)->text));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//errors
|
||||||
|
default: {
|
||||||
|
std::ostringstream msg;
|
||||||
|
msg << "Unknown SerialPacketType encountered in World: " << static_cast<int>(argPacket->type);
|
||||||
|
throw(std::runtime_error(msg.str()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "world.hpp"
|
||||||
|
|
||||||
|
#include "channels.hpp"
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//map management
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void World::SendRegionRequest(int roomIndex, int x, int y) {
|
||||||
|
RegionPacket packet;
|
||||||
|
|
||||||
|
//pack the region's data
|
||||||
|
packet.type = SerialPacketType::REGION_REQUEST;
|
||||||
|
packet.roomIndex = roomIndex;
|
||||||
|
packet.x = x;
|
||||||
|
packet.y = y;
|
||||||
|
|
||||||
|
network.SendTo(Channels::SERVER, &packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hRegionContent(RegionPacket* const argPacket) {
|
||||||
|
//replace existing regions
|
||||||
|
regionPager.UnloadIf([&](Region const& region) -> bool {
|
||||||
|
return region.GetX() == argPacket->x && region.GetY() == argPacket->y;
|
||||||
|
});
|
||||||
|
regionPager.PushRegion(argPacket->region);
|
||||||
|
|
||||||
|
//clean up after the serial code
|
||||||
|
delete argPacket->region;
|
||||||
|
argPacket->region = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::UpdateMap() {
|
||||||
|
if (roomIndex == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//these represent the zone of regions that the client needs loaded, including the mandatory buffers (+1/-1)
|
||||||
|
int xStart = snapToBase(REGION_WIDTH, camera.x/tileSheet.GetTileW()) - REGION_WIDTH;
|
||||||
|
int xEnd = snapToBase(REGION_WIDTH, (camera.x+camera.width)/tileSheet.GetTileW()) + REGION_WIDTH;
|
||||||
|
|
||||||
|
int yStart = snapToBase(REGION_HEIGHT, camera.y/tileSheet.GetTileH()) - REGION_HEIGHT;
|
||||||
|
int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT;
|
||||||
|
|
||||||
|
//prune distant regions
|
||||||
|
regionPager.GetContainer()->remove_if([&](Region const& region) -> bool {
|
||||||
|
return region.GetX() < xStart || region.GetX() > xEnd || region.GetY() < yStart || region.GetY() > yEnd;
|
||||||
|
});
|
||||||
|
|
||||||
|
//request empty regions within this zone
|
||||||
|
for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
|
||||||
|
for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
|
||||||
|
if (!regionPager.FindRegion(i, j)) {
|
||||||
|
SendRegionRequest(roomIndex, i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "world.hpp"
|
||||||
|
|
||||||
|
#include "channels.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//monster management
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void World::hMonsterCreate(MonsterPacket* const argPacket) {
|
||||||
|
//check for logic errors
|
||||||
|
if (monsterMap.find(argPacket->monsterIndex) != monsterMap.end()) {
|
||||||
|
std::ostringstream msg;
|
||||||
|
msg << "Double monster creation event; ";
|
||||||
|
msg << "Index: " << argPacket->monsterIndex << "; ";
|
||||||
|
msg << "Handle: " << argPacket->handle;
|
||||||
|
throw(std::runtime_error(msg.str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//ignore monsters from other rooms
|
||||||
|
if (roomIndex != argPacket->roomIndex) {
|
||||||
|
//temporary error checking
|
||||||
|
std::ostringstream msg;
|
||||||
|
msg << "Monster from the wrong room received: ";
|
||||||
|
msg << "monsterIndex: " << argPacket->monsterIndex << ", roomIndex: " << argPacket->roomIndex;
|
||||||
|
throw(std::runtime_error(msg.str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//implicitly create the element
|
||||||
|
BaseMonster* monster = &monsterMap[argPacket->monsterIndex];
|
||||||
|
|
||||||
|
//fill the monster's info
|
||||||
|
monster->SetHandle(argPacket->handle);
|
||||||
|
monster->SetAvatar(argPacket->avatar);
|
||||||
|
monster->SetBounds(argPacket->bounds);
|
||||||
|
monster->SetOrigin(argPacket->origin);
|
||||||
|
monster->SetMotion(argPacket->motion);
|
||||||
|
|
||||||
|
//debug
|
||||||
|
std::cout << "Monster Create, total: " << monsterMap.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hMonsterDelete(MonsterPacket* const argPacket) {
|
||||||
|
//ignore if this monster doesn't exist
|
||||||
|
std::map<int, BaseMonster>::iterator monsterIt = monsterMap.find(argPacket->monsterIndex);
|
||||||
|
if (monsterIt == monsterMap.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove this monster
|
||||||
|
monsterMap.erase(monsterIt);
|
||||||
|
|
||||||
|
//debug
|
||||||
|
std::cout << "Monster Delete, total: " << monsterMap.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hQueryMonsterExists(MonsterPacket* const argPacket) {
|
||||||
|
//ignore monsters in a different room (sub-optimal)
|
||||||
|
if (argPacket->roomIndex != roomIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//implicitly create the element
|
||||||
|
BaseMonster* monster = &monsterMap[argPacket->monsterIndex];
|
||||||
|
|
||||||
|
//fill the monster's info
|
||||||
|
monster->SetHandle(argPacket->handle);
|
||||||
|
monster->SetAvatar(argPacket->avatar);
|
||||||
|
monster->SetBounds(argPacket->bounds);
|
||||||
|
monster->SetOrigin(argPacket->origin);
|
||||||
|
monster->SetMotion(argPacket->motion);
|
||||||
|
|
||||||
|
//debug
|
||||||
|
std::cout << "Monster Query, total: " << monsterMap.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hQueryMonsterStats(MonsterPacket* const argPacket) {
|
||||||
|
//TODO: (9) World::hQueryMonsterStats()
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hQueryMonsterLocation(MonsterPacket* const argPacket) {
|
||||||
|
//TODO: (9) World::hQueryMonsterLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hMonsterMovement(MonsterPacket* const argPacket) {
|
||||||
|
//ignore if this monster doesn't exist
|
||||||
|
std::map<int, BaseMonster>::iterator monsterIt = monsterMap.find(argPacket->monsterIndex);
|
||||||
|
if (monsterIt == monsterMap.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
monsterIt->second.SetOrigin(argPacket->origin);
|
||||||
|
monsterIt->second.SetOrigin(argPacket->motion);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hMonsterAttack(MonsterPacket* const argPacket) {
|
||||||
|
//TODO: (9) World::hMonsterAttack()
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::hMonsterDamage(MonsterPacket* const argPacket) {
|
||||||
|
//TODO: (9) World::hMonsterDamage()
|
||||||
|
}
|
||||||
+3
-2
@@ -1,5 +1,5 @@
|
|||||||
#include directories
|
#include directories
|
||||||
INCLUDES+=. client_utilities entities scenes ../common/debugging ../common/gameplay ../common/graphics ../common/map ../common/network ../common/network/packet_types ../common/ui ../common/utilities
|
INCLUDES+=. client_utilities entities gameplay_scenes menu_scenes ../common/debugging ../common/gameplay ../common/graphics ../common/map ../common/network ../common/network/packet_types ../common/ui ../common/utilities
|
||||||
|
|
||||||
#libraries
|
#libraries
|
||||||
#the order of the $(LIBS) is important, at least for MinGW
|
#the order of the $(LIBS) is important, at least for MinGW
|
||||||
@@ -27,7 +27,8 @@ OUT=$(addprefix $(OUTDIR)/,client)
|
|||||||
all: $(OBJ) $(OUT)
|
all: $(OBJ) $(OUT)
|
||||||
$(MAKE) -C client_utilities
|
$(MAKE) -C client_utilities
|
||||||
$(MAKE) -C entities
|
$(MAKE) -C entities
|
||||||
$(MAKE) -C scenes
|
$(MAKE) -C gameplay_scenes
|
||||||
|
$(MAKE) -C menu_scenes
|
||||||
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
|
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
|
||||||
|
|
||||||
$(OBJ): | $(OBJDIR)
|
$(OBJ): | $(OBJDIR)
|
||||||
|
|||||||
@@ -22,9 +22,9 @@
|
|||||||
#include "lobby_menu.hpp"
|
#include "lobby_menu.hpp"
|
||||||
|
|
||||||
#include "channels.hpp"
|
#include "channels.hpp"
|
||||||
#include "utility.hpp"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//Public access members
|
//Public access members
|
||||||
@@ -100,14 +100,15 @@ void LobbyMenu::FrameEnd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LobbyMenu::Render(SDL_Surface* const screen) {
|
void LobbyMenu::Render(SDL_Surface* const screen) {
|
||||||
//TODO: I need a proper UI system for the entire client and the editor
|
//TODO: (2) I need a proper UI system for the entire client and the editor
|
||||||
|
|
||||||
//UI
|
//UI
|
||||||
search.DrawTo(screen);
|
search.DrawTo(screen);
|
||||||
join.DrawTo(screen);
|
join.DrawTo(screen);
|
||||||
back.DrawTo(screen);
|
back.DrawTo(screen);
|
||||||
|
|
||||||
//TODO: draw headers for the server list
|
//TODO: (3) draw headers for the server list
|
||||||
|
//TODO: (3) ping/delay displayed in the server list
|
||||||
for (int i = 0; i < serverInfo.size(); i++) {
|
for (int i = 0; i < serverInfo.size(); i++) {
|
||||||
//draw the selected server's highlight
|
//draw the selected server's highlight
|
||||||
if (selection == &serverInfo[i]) {
|
if (selection == &serverInfo[i]) {
|
||||||
@@ -123,14 +124,14 @@ void LobbyMenu::Render(SDL_Surface* const screen) {
|
|||||||
font.DrawStringTo(serverInfo[i].name, screen, listBox.x, listBox.y + i*listBox.h);
|
font.DrawStringTo(serverInfo[i].name, screen, listBox.x, listBox.y + i*listBox.h);
|
||||||
|
|
||||||
//draw the player count
|
//draw the player count
|
||||||
font.DrawStringTo(to_string_custom(serverInfo[i].playerCount), screen, listBox.x + listBox.w, listBox.y + i*listBox.h);
|
std::ostringstream msg;
|
||||||
|
msg << serverInfo[i].playerCount;
|
||||||
|
font.DrawStringTo(msg.str(), screen, listBox.x + listBox.w, listBox.y + i*listBox.h);
|
||||||
|
|
||||||
//compatible?
|
//compatible?
|
||||||
if (!serverInfo[i].compatible) {
|
if (!serverInfo[i].compatible) {
|
||||||
font.DrawStringTo("?", screen, listBox.x - font.GetCharW(), listBox.y + i*listBox.h);
|
font.DrawStringTo("?", screen, listBox.x - font.GetCharW(), listBox.y + i*listBox.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: ping/delay?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,8 +211,11 @@ void LobbyMenu::HandlePacket(SerialPacket* const argPacket) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
//handle errors
|
//handle errors
|
||||||
default:
|
default: {
|
||||||
throw(std::runtime_error(std::string() + "Unknown SerialPacketType encountered in LobbyMenu: " + to_string_custom(static_cast<int>(argPacket->type)) ));
|
std::ostringstream msg;
|
||||||
|
msg << "Unknown SerialPacketType encountered in LobbyMenu: " << static_cast<int>(argPacket->type);
|
||||||
|
throw(std::runtime_error( msg.str() ));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,15 +249,15 @@ void LobbyMenu::HandleLoginResponse(ClientPacket* const argPacket) {
|
|||||||
throw(std::runtime_error("Client index invalid during login"));
|
throw(std::runtime_error("Client index invalid during login"));
|
||||||
}
|
}
|
||||||
accountIndex = argPacket->accountIndex;
|
accountIndex = argPacket->accountIndex;
|
||||||
SetNextScene(SceneList::INWORLD);
|
SetNextScene(SceneList::WORLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) {
|
void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) {
|
||||||
//TODO: Better output for join rejection
|
//TODO: (9) LobbyMenu::HandleJoinRejection()
|
||||||
}
|
}
|
||||||
|
|
||||||
void LobbyMenu::HandleLoginRejection(TextPacket* const argPacket) {
|
void LobbyMenu::HandleLoginRejection(TextPacket* const argPacket) {
|
||||||
//TODO: Better output for login rejection
|
//TODO: (9) LobbyMenu::HandleLoginRejection
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
@@ -84,6 +84,11 @@ void MainMenu::Render(SDL_Surface* const screen) {
|
|||||||
startButton.DrawTo(screen);
|
startButton.DrawTo(screen);
|
||||||
optionsButton.DrawTo(screen);
|
optionsButton.DrawTo(screen);
|
||||||
quitButton.DrawTo(screen);
|
quitButton.DrawTo(screen);
|
||||||
|
|
||||||
|
//text
|
||||||
|
font.DrawStringTo("Thanks for playing!", screen, 50, screen->h - 50 - image.GetClipH() * 2);
|
||||||
|
font.DrawStringTo("You can get the latest version at: ", screen, 50, screen->h - 50 - image.GetClipH() * 1);
|
||||||
|
font.DrawStringTo("krgamestudios.com", screen, 50, screen->h - 50 - image.GetClipH() * 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
@@ -103,7 +108,7 @@ void MainMenu::MouseButtonDown(SDL_MouseButtonEvent const& button) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
|
void MainMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
|
||||||
//TODO: Buttons should only register as "selected" when the left button is used
|
//TODO: (2) Buttons should only register as "selected" when the left button is used
|
||||||
if (startButton.MouseButtonUp(button) == Button::State::HOVER) {
|
if (startButton.MouseButtonUp(button) == Button::State::HOVER) {
|
||||||
SetNextScene(SceneList::LOBBYMENU);
|
SetNextScene(SceneList::LOBBYMENU);
|
||||||
}
|
}
|
||||||
@@ -120,5 +125,9 @@ void MainMenu::KeyDown(SDL_KeyboardEvent const& key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainMenu::KeyUp(SDL_KeyboardEvent const& key) {
|
void MainMenu::KeyUp(SDL_KeyboardEvent const& key) {
|
||||||
//
|
switch(key.keysym.sym) {
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
QuitEvent();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#config
|
||||||
|
INCLUDES+=. .. ../../common/graphics ../../common/map ../../common/network ../../common/network/packet_types ../../common/ui ../../common/utilities
|
||||||
|
LIBS+=
|
||||||
|
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
||||||
|
|
||||||
|
#source
|
||||||
|
CXXSRC=$(wildcard *.cpp)
|
||||||
|
|
||||||
|
#objects
|
||||||
|
OBJDIR=obj
|
||||||
|
OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o))
|
||||||
|
|
||||||
|
#output
|
||||||
|
OUTDIR=..
|
||||||
|
OUT=$(addprefix $(OUTDIR)/,client.a)
|
||||||
|
|
||||||
|
#targets
|
||||||
|
all: $(OBJ) $(OUT)
|
||||||
|
ar -crs $(OUT) $(OBJ)
|
||||||
|
|
||||||
|
$(OBJ): | $(OBJDIR)
|
||||||
|
|
||||||
|
$(OUT): | $(OUTDIR)
|
||||||
|
|
||||||
|
$(OBJDIR):
|
||||||
|
mkdir $(OBJDIR)
|
||||||
|
|
||||||
|
$(OUTDIR):
|
||||||
|
mkdir $(OUTDIR)
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o: %.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) *.o *.a *.exe
|
||||||
|
|
||||||
|
rebuild: clean all
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
#include "raster_font.hpp"
|
#include "raster_font.hpp"
|
||||||
#include "button.hpp"
|
#include "button.hpp"
|
||||||
|
|
||||||
//TODO: The options screen needs to be USED
|
//NOTE: The options screen needs to be USED
|
||||||
class OptionsMenu : public BaseScene {
|
class OptionsMenu : public BaseScene {
|
||||||
public:
|
public:
|
||||||
//Public access members
|
//Public access members
|
||||||
@@ -33,7 +33,7 @@ enum class SceneList {
|
|||||||
MAINMENU,
|
MAINMENU,
|
||||||
OPTIONSMENU,
|
OPTIONSMENU,
|
||||||
LOBBYMENU,
|
LOBBYMENU,
|
||||||
INWORLD,
|
WORLD,
|
||||||
DISCONNECTEDSCREEN,
|
DISCONNECTEDSCREEN,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,731 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013-2015
|
|
||||||
*
|
|
||||||
* This software is provided 'as-is', without any express or implied
|
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
|
||||||
* arising from the use of this software.
|
|
||||||
*
|
|
||||||
* Permission is granted to anyone to use this software for any purpose,
|
|
||||||
* including commercial applications, and to alter it and redistribute it
|
|
||||||
* freely, subject to the following restrictions:
|
|
||||||
*
|
|
||||||
* 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
* claim that you wrote the original software. If you use this software
|
|
||||||
* in a product, an acknowledgment in the product documentation would be
|
|
||||||
* appreciated but is not required.
|
|
||||||
*
|
|
||||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
* misrepresented as being the original software.
|
|
||||||
*
|
|
||||||
* 3. This notice may not be removed or altered from any source
|
|
||||||
* distribution.
|
|
||||||
*/
|
|
||||||
#include "in_world.hpp"
|
|
||||||
|
|
||||||
#include "channels.hpp"
|
|
||||||
#include "utility.hpp"
|
|
||||||
|
|
||||||
#include "terminal_error.hpp"
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cmath>
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//these should've come standard
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
bool operator==(IPaddress lhs, IPaddress rhs) {
|
|
||||||
return lhs.host == rhs.host && lhs.port == rhs.port;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(IPaddress lhs, IPaddress rhs) {
|
|
||||||
return !(lhs == rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Public access members
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex):
|
|
||||||
clientIndex(*argClientIndex),
|
|
||||||
accountIndex(*argAccountIndex)
|
|
||||||
{
|
|
||||||
//setup the utility objects
|
|
||||||
buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp");
|
|
||||||
buttonImage.SetClipH(buttonImage.GetClipH()/3);
|
|
||||||
font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp");
|
|
||||||
|
|
||||||
//pass the utility objects
|
|
||||||
disconnectButton.SetImage(&buttonImage);
|
|
||||||
disconnectButton.SetFont(&font);
|
|
||||||
shutDownButton.SetImage(&buttonImage);
|
|
||||||
shutDownButton.SetFont(&font);
|
|
||||||
|
|
||||||
//set the button positions
|
|
||||||
disconnectButton.SetX(50);
|
|
||||||
disconnectButton.SetY(50 + buttonImage.GetClipH() * 0);
|
|
||||||
shutDownButton.SetX(50);
|
|
||||||
shutDownButton.SetY(50 + buttonImage.GetClipH() * 1);
|
|
||||||
|
|
||||||
//set the button texts
|
|
||||||
disconnectButton.SetText("Disconnect");
|
|
||||||
shutDownButton.SetText("Shut Down");
|
|
||||||
|
|
||||||
//load the tilesheet
|
|
||||||
//TODO: add the tilesheet to the map system
|
|
||||||
//TODO: Tile size and tile sheet should be loaded elsewhere
|
|
||||||
tileSheet.Load(config["dir.tilesets"] + "overworld.bmp", 32, 32);
|
|
||||||
|
|
||||||
//Send the character data
|
|
||||||
//TODO: login scene, prompt, etc.
|
|
||||||
CharacterPacket newPacket;
|
|
||||||
newPacket.type = SerialPacketType::CHARACTER_LOAD;
|
|
||||||
strncpy(newPacket.handle, config["client.handle"].c_str(), PACKET_STRING_SIZE);
|
|
||||||
strncpy(newPacket.avatar, config["client.avatar"].c_str(), PACKET_STRING_SIZE);
|
|
||||||
newPacket.accountIndex = accountIndex;
|
|
||||||
network.SendTo(Channels::SERVER, &newPacket);
|
|
||||||
|
|
||||||
//query the world state
|
|
||||||
memset(&newPacket, 0, MAX_PACKET_SIZE);
|
|
||||||
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
|
|
||||||
network.SendTo(Channels::SERVER, &newPacket);
|
|
||||||
|
|
||||||
//set the camera's values
|
|
||||||
camera.width = GetScreen()->w;
|
|
||||||
camera.height = GetScreen()->h;
|
|
||||||
|
|
||||||
//debug
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
InWorld::~InWorld() {
|
|
||||||
//unload the local data
|
|
||||||
characterMap.clear();
|
|
||||||
monsterMap.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Frame loop
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void InWorld::FrameStart() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::Update() {
|
|
||||||
//create and zero the buffer
|
|
||||||
SerialPacket* packetBuffer = reinterpret_cast<SerialPacket*>(new char[MAX_PACKET_SIZE]);
|
|
||||||
memset(packetBuffer, 0, MAX_PACKET_SIZE);
|
|
||||||
|
|
||||||
try {
|
|
||||||
//suck in and process all waiting packets
|
|
||||||
while(network.Receive(packetBuffer)) {
|
|
||||||
HandlePacket(packetBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(terminal_error& e) {
|
|
||||||
throw(e);
|
|
||||||
}
|
|
||||||
catch(std::exception& e) {
|
|
||||||
std::cerr << "HandlePacket Error: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
//free the buffer
|
|
||||||
delete reinterpret_cast<char*>(packetBuffer);
|
|
||||||
|
|
||||||
//check the connection (heartbeat)
|
|
||||||
if (Clock::now() - lastBeat > std::chrono::seconds(3)) {
|
|
||||||
if (attemptedBeats > 2) {
|
|
||||||
//escape to the disconnect screen
|
|
||||||
SendDisconnectRequest();
|
|
||||||
SetNextScene(SceneList::DISCONNECTEDSCREEN);
|
|
||||||
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "Error: Lost connection to the server";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ServerPacket newPacket;
|
|
||||||
newPacket.type = SerialPacketType::PING;
|
|
||||||
network.SendTo(Channels::SERVER, &newPacket);
|
|
||||||
|
|
||||||
attemptedBeats++;
|
|
||||||
lastBeat = Clock::now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//update all entities
|
|
||||||
for (auto& it : characterMap) {
|
|
||||||
// it.second.Update();
|
|
||||||
}
|
|
||||||
for (auto& it : monsterMap) {
|
|
||||||
it.second.Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
//update the map
|
|
||||||
UpdateMap();
|
|
||||||
|
|
||||||
//skip the rest without a local character
|
|
||||||
if (!localCharacter) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//prepare for collisions
|
|
||||||
BoundingBox wallBounds = {0, 0, tileSheet.GetTileW(), tileSheet.GetTileH()};
|
|
||||||
std::list<BoundingBox> boxList;
|
|
||||||
|
|
||||||
//NOTE: for loops were too dense to work with, so I've just used while loops
|
|
||||||
//NOTE: this code is complex, and can be replaced with hard-coded relative positions, at the cost of variable-sized sprites/bounding boxes
|
|
||||||
|
|
||||||
//outer loop
|
|
||||||
wallBounds.x = snapToBase((double)wallBounds.w, localCharacter->GetOrigin().x) - wallBounds.w;
|
|
||||||
while(wallBounds.x < (localCharacter->GetOrigin() + localCharacter->GetBounds()).x + localCharacter->GetBounds().w) {
|
|
||||||
//inner loop
|
|
||||||
wallBounds.y = snapToBase((double)wallBounds.h, localCharacter->GetOrigin().y) - wallBounds.h;
|
|
||||||
while(wallBounds.y < (localCharacter->GetOrigin() + localCharacter->GetBounds()).y + localCharacter->GetBounds().h) {
|
|
||||||
//check to see if this tile is solid
|
|
||||||
if (regionPager.GetSolid(wallBounds.x / wallBounds.w, wallBounds.y / wallBounds.h)) {
|
|
||||||
//push onto the box set
|
|
||||||
boxList.push_front(wallBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
//increment
|
|
||||||
wallBounds.y += wallBounds.h;
|
|
||||||
}
|
|
||||||
|
|
||||||
//increment
|
|
||||||
wallBounds.x += wallBounds.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
//process the collisions
|
|
||||||
localCharacter->ProcessCollisions(boxList);
|
|
||||||
|
|
||||||
//update the camera
|
|
||||||
camera.x = localCharacter->GetOrigin().x - camera.marginX;
|
|
||||||
camera.y = localCharacter->GetOrigin().y - camera.marginY;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::FrameEnd() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::RenderFrame() {
|
|
||||||
SDL_FillRect(GetScreen(), 0, 0);
|
|
||||||
Render(GetScreen());
|
|
||||||
SDL_Flip(GetScreen());
|
|
||||||
fps.Calculate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::Render(SDL_Surface* const screen) {
|
|
||||||
//draw the map
|
|
||||||
for (std::list<Region>::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
|
|
||||||
tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
//draw the entities
|
|
||||||
for (auto& it : characterMap) {
|
|
||||||
//TODO: depth ordering
|
|
||||||
it.second.DrawTo(screen, camera.x, camera.y);
|
|
||||||
}
|
|
||||||
for (auto& it : monsterMap) {
|
|
||||||
//TODO: depth ordering
|
|
||||||
it.second.DrawTo(screen, camera.x, camera.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
//draw UI
|
|
||||||
disconnectButton.DrawTo(screen);
|
|
||||||
shutDownButton.DrawTo(screen);
|
|
||||||
font.DrawStringTo(to_string_custom(fps.GetFrameRate()), screen, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Event handlers
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void InWorld::QuitEvent() {
|
|
||||||
//two-step logout
|
|
||||||
SendDisconnectRequest();
|
|
||||||
SetNextScene(SceneList::QUIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::MouseMotion(SDL_MouseMotionEvent const& motion) {
|
|
||||||
disconnectButton.MouseMotion(motion);
|
|
||||||
shutDownButton.MouseMotion(motion);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::MouseButtonDown(SDL_MouseButtonEvent const& button) {
|
|
||||||
disconnectButton.MouseButtonDown(button);
|
|
||||||
shutDownButton.MouseButtonDown(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::MouseButtonUp(SDL_MouseButtonEvent const& button) {
|
|
||||||
if (disconnectButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) {
|
|
||||||
SendLogoutRequest();
|
|
||||||
}
|
|
||||||
if (shutDownButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) {
|
|
||||||
SendShutdownRequest();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::KeyDown(SDL_KeyboardEvent const& key) {
|
|
||||||
//hotkeys
|
|
||||||
switch(key.keysym.sym) {
|
|
||||||
case SDLK_ESCAPE:
|
|
||||||
//TODO: the escape key should actually control menus and stuff
|
|
||||||
SendLogoutRequest();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//character movement
|
|
||||||
if (!localCharacter) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Vector2 motion = localCharacter->GetMotion();
|
|
||||||
switch(key.keysym.sym) {
|
|
||||||
case SDLK_w:
|
|
||||||
motion.y -= CHARACTER_WALKING_SPEED;
|
|
||||||
break;
|
|
||||||
case SDLK_a:
|
|
||||||
motion.x -= CHARACTER_WALKING_SPEED;
|
|
||||||
break;
|
|
||||||
case SDLK_s:
|
|
||||||
motion.y += CHARACTER_WALKING_SPEED;
|
|
||||||
break;
|
|
||||||
case SDLK_d:
|
|
||||||
motion.x += CHARACTER_WALKING_SPEED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
//DOCS: prevents wrong keys screwing with character movement
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//handle diagonals
|
|
||||||
if (motion.x != 0 && motion.y != 0) {
|
|
||||||
motion *= CHARACTER_WALKING_MOD;
|
|
||||||
}
|
|
||||||
//set the info
|
|
||||||
localCharacter->SetMotion(motion);
|
|
||||||
localCharacter->CorrectSprite();
|
|
||||||
SendLocalCharacterMotion();
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::KeyUp(SDL_KeyboardEvent const& key) {
|
|
||||||
//character movement
|
|
||||||
if (!localCharacter) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Vector2 motion = localCharacter->GetMotion();
|
|
||||||
switch(key.keysym.sym) {
|
|
||||||
case SDLK_w:
|
|
||||||
motion.y = std::min(0.0, motion.y += CHARACTER_WALKING_SPEED);
|
|
||||||
break;
|
|
||||||
case SDLK_a:
|
|
||||||
motion.x = std::min(0.0, motion.x += CHARACTER_WALKING_SPEED);
|
|
||||||
break;
|
|
||||||
case SDLK_s:
|
|
||||||
motion.y = std::max(0.0, motion.y -= CHARACTER_WALKING_SPEED);
|
|
||||||
break;
|
|
||||||
case SDLK_d:
|
|
||||||
motion.x = std::max(0.0, motion.x -= CHARACTER_WALKING_SPEED);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
//DOCS: prevents wrong keys screwing with character movement
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//BUGFIX: reset cardinal direction speed on key release
|
|
||||||
if (motion.x > 0) {
|
|
||||||
motion.x = CHARACTER_WALKING_SPEED;
|
|
||||||
}
|
|
||||||
else if (motion.x < 0) {
|
|
||||||
motion.x = -CHARACTER_WALKING_SPEED;
|
|
||||||
}
|
|
||||||
if (motion.y > 0) {
|
|
||||||
motion.y = CHARACTER_WALKING_SPEED;
|
|
||||||
}
|
|
||||||
else if (motion.y < 0) {
|
|
||||||
motion.y = -CHARACTER_WALKING_SPEED;
|
|
||||||
}
|
|
||||||
//handle diagonals
|
|
||||||
if (motion.x != 0 && motion.y != 0) {
|
|
||||||
motion *= CHARACTER_WALKING_MOD;
|
|
||||||
}
|
|
||||||
//set the info
|
|
||||||
localCharacter->SetMotion(motion);
|
|
||||||
localCharacter->CorrectSprite();
|
|
||||||
SendLocalCharacterMotion();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Basic connections
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void InWorld::HandlePacket(SerialPacket* const argPacket) {
|
|
||||||
switch(argPacket->type) {
|
|
||||||
//heartbeat system
|
|
||||||
case SerialPacketType::PING:
|
|
||||||
HandlePing(static_cast<ServerPacket*>(argPacket));
|
|
||||||
break;
|
|
||||||
case SerialPacketType::PONG:
|
|
||||||
HandlePong(static_cast<ServerPacket*>(argPacket));
|
|
||||||
break;
|
|
||||||
|
|
||||||
//game server connections
|
|
||||||
case SerialPacketType::LOGOUT_RESPONSE:
|
|
||||||
HandleLogoutResponse(static_cast<ClientPacket*>(argPacket));
|
|
||||||
break;
|
|
||||||
case SerialPacketType::DISCONNECT_RESPONSE:
|
|
||||||
HandleDisconnectResponse(static_cast<ClientPacket*>(argPacket));
|
|
||||||
break;
|
|
||||||
case SerialPacketType::DISCONNECT_FORCED:
|
|
||||||
HandleDisconnectForced(static_cast<ClientPacket*>(argPacket));
|
|
||||||
break;
|
|
||||||
|
|
||||||
//map management
|
|
||||||
case SerialPacketType::REGION_CONTENT:
|
|
||||||
HandleRegionContent(static_cast<RegionPacket*>(argPacket));
|
|
||||||
break;
|
|
||||||
|
|
||||||
//character management
|
|
||||||
case SerialPacketType::CHARACTER_CREATE:
|
|
||||||
HandleCharacterCreate(static_cast<CharacterPacket*>(argPacket));
|
|
||||||
break;
|
|
||||||
case SerialPacketType::CHARACTER_DELETE:
|
|
||||||
HandleCharacterDelete(static_cast<CharacterPacket*>(argPacket));
|
|
||||||
break;
|
|
||||||
case SerialPacketType::QUERY_CHARACTER_EXISTS:
|
|
||||||
HandleCharacterQueryExists(static_cast<CharacterPacket*>(argPacket));
|
|
||||||
break;
|
|
||||||
|
|
||||||
//character movement
|
|
||||||
case SerialPacketType::CHARACTER_SET_ROOM:
|
|
||||||
HandleCharacterSetRoom(static_cast<CharacterPacket*>(argPacket));
|
|
||||||
break;
|
|
||||||
case SerialPacketType::CHARACTER_SET_ORIGIN:
|
|
||||||
HandleCharacterSetOrigin(static_cast<CharacterPacket*>(argPacket));
|
|
||||||
break;
|
|
||||||
case SerialPacketType::CHARACTER_SET_MOTION:
|
|
||||||
HandleCharacterSetMotion(static_cast<CharacterPacket*>(argPacket));
|
|
||||||
break;
|
|
||||||
|
|
||||||
//rejection messages
|
|
||||||
case SerialPacketType::REGION_REJECTION:
|
|
||||||
case SerialPacketType::CHARACTER_REJECTION:
|
|
||||||
throw(terminal_error(static_cast<TextPacket*>(argPacket)->text));
|
|
||||||
break;
|
|
||||||
case SerialPacketType::SHUTDOWN_REJECTION:
|
|
||||||
throw(std::runtime_error(static_cast<TextPacket*>(argPacket)->text));
|
|
||||||
break;
|
|
||||||
|
|
||||||
//errors
|
|
||||||
default: {
|
|
||||||
std::ostringstream msg;
|
|
||||||
msg << "Unknown SerialPacketType encountered in InWorld: " << static_cast<int>(argPacket->type);
|
|
||||||
throw(std::runtime_error(msg.str()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::HandlePing(ServerPacket* const argPacket) {
|
|
||||||
ServerPacket newPacket;
|
|
||||||
newPacket.type = SerialPacketType::PONG;
|
|
||||||
network.SendTo(argPacket->srcAddress, &newPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::HandlePong(ServerPacket* const argPacket) {
|
|
||||||
if (*network.GetIPAddress(Channels::SERVER) != argPacket->srcAddress) {
|
|
||||||
throw(std::runtime_error("Heartbeat message received from an unknown source"));
|
|
||||||
}
|
|
||||||
attemptedBeats = 0;
|
|
||||||
lastBeat = Clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Connection control
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void InWorld::SendLogoutRequest() {
|
|
||||||
ClientPacket newPacket;
|
|
||||||
|
|
||||||
//send a logout request
|
|
||||||
newPacket.type = SerialPacketType::LOGOUT_REQUEST;
|
|
||||||
newPacket.accountIndex = accountIndex;
|
|
||||||
|
|
||||||
network.SendTo(Channels::SERVER, &newPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::SendDisconnectRequest() {
|
|
||||||
ClientPacket newPacket;
|
|
||||||
|
|
||||||
//send a disconnect request
|
|
||||||
newPacket.type = SerialPacketType::DISCONNECT_REQUEST;
|
|
||||||
newPacket.clientIndex = clientIndex;
|
|
||||||
|
|
||||||
network.SendTo(Channels::SERVER, &newPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::SendShutdownRequest() {
|
|
||||||
ClientPacket newPacket;
|
|
||||||
|
|
||||||
//send a shutdown request
|
|
||||||
newPacket.type = SerialPacketType::SHUTDOWN_REQUEST;
|
|
||||||
newPacket.accountIndex = accountIndex;
|
|
||||||
|
|
||||||
network.SendTo(Channels::SERVER, &newPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::HandleLogoutResponse(ClientPacket* const argPacket) {
|
|
||||||
if (localCharacter) {
|
|
||||||
characterMap.erase(characterIndex);
|
|
||||||
localCharacter = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
accountIndex = -1;
|
|
||||||
characterIndex = -1;
|
|
||||||
|
|
||||||
//reset the camera
|
|
||||||
camera.marginX = camera.marginY = 0;
|
|
||||||
|
|
||||||
//because, why not? I guess...
|
|
||||||
SendDisconnectRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::HandleDisconnectResponse(ClientPacket* const argPacket) {
|
|
||||||
HandleLogoutResponse(argPacket);//shortcut
|
|
||||||
SetNextScene(SceneList::DISCONNECTEDSCREEN);
|
|
||||||
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have successfully logged out";
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::HandleDisconnectForced(ClientPacket* const argPacket) {
|
|
||||||
HandleDisconnectResponse(argPacket);//shortcut
|
|
||||||
SetNextScene(SceneList::DISCONNECTEDSCREEN);
|
|
||||||
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have been forcibly disconnected by the server";
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//map management
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void InWorld::SendRegionRequest(int roomIndex, int x, int y) {
|
|
||||||
RegionPacket packet;
|
|
||||||
|
|
||||||
//pack the region's data
|
|
||||||
packet.type = SerialPacketType::REGION_REQUEST;
|
|
||||||
packet.roomIndex = roomIndex;
|
|
||||||
packet.x = x;
|
|
||||||
packet.y = y;
|
|
||||||
|
|
||||||
network.SendTo(Channels::SERVER, &packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::HandleRegionContent(RegionPacket* const argPacket) {
|
|
||||||
//replace existing regions
|
|
||||||
regionPager.UnloadRegion(argPacket->x, argPacket->y);
|
|
||||||
regionPager.PushRegion(argPacket->region);
|
|
||||||
|
|
||||||
//clean up after the serial code
|
|
||||||
delete argPacket->region;
|
|
||||||
argPacket->region = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::UpdateMap() {
|
|
||||||
if (roomIndex == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//these represent the zone of regions that the client needs loaded, including the mandatory buffers (+1/-1)
|
|
||||||
int xStart = snapToBase(REGION_WIDTH, camera.x/tileSheet.GetTileW()) - REGION_WIDTH;
|
|
||||||
int xEnd = snapToBase(REGION_WIDTH, (camera.x+camera.width)/tileSheet.GetTileW()) + REGION_WIDTH;
|
|
||||||
|
|
||||||
int yStart = snapToBase(REGION_HEIGHT, camera.y/tileSheet.GetTileH()) - REGION_HEIGHT;
|
|
||||||
int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT;
|
|
||||||
|
|
||||||
//prune distant regions
|
|
||||||
regionPager.GetContainer()->remove_if([&](Region const& region) -> bool {
|
|
||||||
return region.GetX() < xStart || region.GetX() > xEnd || region.GetY() < yStart || region.GetY() > yEnd;
|
|
||||||
});
|
|
||||||
|
|
||||||
//request empty regions within this zone
|
|
||||||
for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
|
|
||||||
for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
|
|
||||||
if (!regionPager.FindRegion(i, j)) {
|
|
||||||
SendRegionRequest(roomIndex, i, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//entity management
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
//NOTE: preexisting characters will result in query responses
|
|
||||||
//NOTE: new characters will result in create messages
|
|
||||||
//NOTE: this client's character will exist in both (skipped)
|
|
||||||
|
|
||||||
void InWorld::HandleCharacterCreate(CharacterPacket* const argPacket) {
|
|
||||||
//prevent double message
|
|
||||||
if (characterMap.find(argPacket->characterIndex) != characterMap.end()) {
|
|
||||||
std::ostringstream msg;
|
|
||||||
msg << "Double character creation event; ";
|
|
||||||
msg << "Index: " << argPacket->characterIndex << "; ";
|
|
||||||
msg << "Handle: " << argPacket->handle;
|
|
||||||
throw(std::runtime_error(msg.str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
//implicity create and retrieve the entity
|
|
||||||
BaseCharacter* character = &characterMap[argPacket->characterIndex];
|
|
||||||
|
|
||||||
//fill the character's info
|
|
||||||
character->SetOrigin(argPacket->origin);
|
|
||||||
character->SetMotion(argPacket->motion);
|
|
||||||
character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT});
|
|
||||||
character->SetHandle(argPacket->handle);
|
|
||||||
character->SetAvatar(argPacket->avatar);
|
|
||||||
character->SetOwner(argPacket->accountIndex);
|
|
||||||
character->CorrectSprite();
|
|
||||||
|
|
||||||
//check for this player's character
|
|
||||||
if (character->GetOwner() == accountIndex) {
|
|
||||||
localCharacter = static_cast<LocalCharacter*>(character);
|
|
||||||
|
|
||||||
//focus the camera on this character
|
|
||||||
camera.marginX = (camera.width / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2);
|
|
||||||
camera.marginY = (camera.height/ 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2);
|
|
||||||
|
|
||||||
//focus on this character's info
|
|
||||||
characterIndex = argPacket->characterIndex;
|
|
||||||
roomIndex = argPacket->roomIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
//debug
|
|
||||||
std::cout << "Create, total: " << characterMap.size() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::HandleCharacterDelete(CharacterPacket* const argPacket) {
|
|
||||||
//ignore if this character doesn't exist
|
|
||||||
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
|
|
||||||
if (characterIt == characterMap.end()) {
|
|
||||||
//debug
|
|
||||||
std::cout << "Ignoring character deletion" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//check for this player's character
|
|
||||||
if ((*characterIt).second.GetOwner() == accountIndex) {
|
|
||||||
localCharacter = nullptr;
|
|
||||||
|
|
||||||
//clear the camera
|
|
||||||
camera.marginX = 0;
|
|
||||||
camera.marginY = 0;
|
|
||||||
|
|
||||||
//clear the room
|
|
||||||
roomIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//remove this character
|
|
||||||
characterMap.erase(characterIt);
|
|
||||||
|
|
||||||
//debug
|
|
||||||
std::cout << "Delete, total: " << characterMap.size() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::HandleCharacterQueryExists(CharacterPacket* const argPacket) {
|
|
||||||
//prevent a double message about this player's character
|
|
||||||
if (argPacket->accountIndex == accountIndex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//ignore characters in a different room (sub-optimal)
|
|
||||||
if (argPacket->roomIndex != roomIndex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//implicitly construct the character if it doesn't exist
|
|
||||||
BaseCharacter* character = &characterMap[argPacket->characterIndex];
|
|
||||||
|
|
||||||
//set/update the character's info
|
|
||||||
character->SetOrigin(argPacket->origin);
|
|
||||||
character->SetMotion(argPacket->motion);
|
|
||||||
character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT});
|
|
||||||
character->SetHandle(argPacket->handle);
|
|
||||||
character->SetAvatar(argPacket->avatar);
|
|
||||||
character->SetOwner(argPacket->accountIndex);
|
|
||||||
character->CorrectSprite();
|
|
||||||
|
|
||||||
//debug
|
|
||||||
std::cout << "Query, total: " << characterMap.size() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::HandleCharacterSetRoom(CharacterPacket* const argPacket) {
|
|
||||||
//someone else's character
|
|
||||||
if (argPacket->characterIndex != characterIndex) {
|
|
||||||
characterMap.erase(argPacket->characterIndex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//this character is moving between rooms
|
|
||||||
roomIndex = argPacket->roomIndex;
|
|
||||||
|
|
||||||
//set the character's info
|
|
||||||
localCharacter->SetOrigin(argPacket->origin);
|
|
||||||
localCharacter->SetMotion(argPacket->motion);
|
|
||||||
localCharacter->CorrectSprite();
|
|
||||||
|
|
||||||
//clear the old room's data
|
|
||||||
regionPager.UnloadAll();
|
|
||||||
monsterMap.clear();
|
|
||||||
|
|
||||||
//use the jenky pattern for std::map to skip this player's character
|
|
||||||
for (std::map<int, BaseCharacter>::iterator it = characterMap.begin(); it != characterMap.end(); /* EMPTY */ ) {
|
|
||||||
if (it->first != characterIndex) {
|
|
||||||
it = characterMap.erase(it);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//request the info on characters in this room
|
|
||||||
CharacterPacket newPacket;
|
|
||||||
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
|
|
||||||
newPacket.roomIndex = roomIndex;
|
|
||||||
network.SendTo(Channels::SERVER, &newPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::HandleCharacterSetOrigin(CharacterPacket* const argPacket) {
|
|
||||||
//check that this character exists
|
|
||||||
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
|
|
||||||
if (characterIt != characterMap.end()) {
|
|
||||||
//set the origin and motion
|
|
||||||
characterIt->second.SetOrigin(argPacket->origin);
|
|
||||||
characterIt->second.SetMotion(argPacket->motion);
|
|
||||||
characterIt->second.CorrectSprite();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::HandleCharacterSetMotion(CharacterPacket* const argPacket) {
|
|
||||||
//check that this character exists
|
|
||||||
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
|
|
||||||
if (characterIt != characterMap.end()) {
|
|
||||||
//set the origin and motion
|
|
||||||
characterIt->second.SetOrigin(argPacket->origin);
|
|
||||||
characterIt->second.SetMotion(argPacket->motion);
|
|
||||||
characterIt->second.CorrectSprite();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//player movement
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
//TODO: add a "movement" packet type
|
|
||||||
void InWorld::SendLocalCharacterMotion() {
|
|
||||||
CharacterPacket newPacket;
|
|
||||||
newPacket.type = SerialPacketType::CHARACTER_SET_MOTION;
|
|
||||||
|
|
||||||
newPacket.accountIndex = accountIndex;
|
|
||||||
newPacket.characterIndex = characterIndex;
|
|
||||||
newPacket.roomIndex = roomIndex;
|
|
||||||
newPacket.origin = localCharacter->GetOrigin();
|
|
||||||
newPacket.motion = localCharacter->GetMotion();
|
|
||||||
|
|
||||||
network.SendTo(Channels::SERVER, &newPacket);
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#config
|
#config
|
||||||
INCLUDES+=.
|
INCLUDES+=. ../map
|
||||||
LIBS+=
|
LIBS+=
|
||||||
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#config
|
#config
|
||||||
INCLUDES+=. ../graphics ../utilities
|
INCLUDES+=. ../utilities
|
||||||
LIBS+=
|
LIBS+=
|
||||||
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
||||||
|
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013-2015
|
|
||||||
*
|
|
||||||
* This software is provided 'as-is', without any express or implied
|
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
|
||||||
* arising from the use of this software.
|
|
||||||
*
|
|
||||||
* Permission is granted to anyone to use this software for any purpose,
|
|
||||||
* including commercial applications, and to alter it and redistribute it
|
|
||||||
* freely, subject to the following restrictions:
|
|
||||||
*
|
|
||||||
* 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
* claim that you wrote the original software. If you use this software
|
|
||||||
* in a product, an acknowledgment in the product documentation would be
|
|
||||||
* appreciated but is not required.
|
|
||||||
*
|
|
||||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
* misrepresented as being the original software.
|
|
||||||
*
|
|
||||||
* 3. This notice may not be removed or altered from any source
|
|
||||||
* distribution.
|
|
||||||
*/
|
|
||||||
#include "map_system_api.hpp"
|
|
||||||
|
|
||||||
//all map API headers
|
|
||||||
#include "region_api.hpp"
|
|
||||||
#include "region_pager_api.hpp"
|
|
||||||
#include "tile_sheet_api.hpp"
|
|
||||||
|
|
||||||
//macros
|
|
||||||
#include "region.hpp"
|
|
||||||
|
|
||||||
//useful "globals"
|
|
||||||
static int getRegionWidth(lua_State* L) {
|
|
||||||
lua_pushinteger(L, REGION_WIDTH);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getRegionHeight(lua_State* L) {
|
|
||||||
lua_pushinteger(L, REGION_HEIGHT);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getRegionDepth(lua_State* L) {
|
|
||||||
lua_pushinteger(L, REGION_DEPTH);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//This mimics linit.c to create a nested collection of all map modules.
|
|
||||||
static const luaL_Reg funcs[] = {
|
|
||||||
//synonyms
|
|
||||||
{"GetRegionWidth", getRegionWidth},
|
|
||||||
{"GetRegionHeight", getRegionHeight},
|
|
||||||
{"GetRegionDepth", getRegionDepth},
|
|
||||||
{nullptr, nullptr}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const luaL_Reg libs[] = {
|
|
||||||
{"Region", openRegionAPI},
|
|
||||||
{"RegionPager", openRegionPagerAPI},
|
|
||||||
// {"TileSheet", openTileSheetAPI},
|
|
||||||
{nullptr, nullptr}
|
|
||||||
};
|
|
||||||
|
|
||||||
int openMapSystemAPI(lua_State* L) {
|
|
||||||
//create the table
|
|
||||||
luaL_newlibtable(L, libs);
|
|
||||||
|
|
||||||
//push the "global" functions
|
|
||||||
luaL_setfuncs(L, funcs, 0);
|
|
||||||
|
|
||||||
//push the substable
|
|
||||||
for (const luaL_Reg* lib = libs; lib->func; lib++) {
|
|
||||||
lib->func(L);
|
|
||||||
lua_setfield(L, -2, lib->name);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
+25
-1
@@ -21,9 +21,9 @@
|
|||||||
*/
|
*/
|
||||||
#include "region.hpp"
|
#include "region.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
int snapToBase(int base, int x) {
|
int snapToBase(int base, int x) {
|
||||||
return floor((double)x / base) * base;
|
return floor((double)x / base) * base;
|
||||||
@@ -42,17 +42,41 @@ Region::Region(Region const& rhs): x(rhs.x), y(rhs.y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Region::type_t Region::SetTile(int x, int y, int z, type_t v) {
|
Region::type_t Region::SetTile(int x, int y, int z, type_t v) {
|
||||||
|
if (x < 0 || y < 0 || z < 0 || x >= REGION_WIDTH || y >= REGION_HEIGHT || z >= REGION_DEPTH) {
|
||||||
|
throw(std::out_of_range("Region::SetTile() argument out of range"));
|
||||||
|
}
|
||||||
return tiles[x][y][z] = v;
|
return tiles[x][y][z] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
Region::type_t Region::GetTile(int x, int y, int z) {
|
Region::type_t Region::GetTile(int x, int y, int z) {
|
||||||
|
if (x < 0 || y < 0 || z < 0 || x >= REGION_WIDTH || y >= REGION_HEIGHT || z >= REGION_DEPTH) {
|
||||||
|
throw(std::out_of_range("Region::GetTile() argument out of range"));
|
||||||
|
}
|
||||||
return tiles[x][y][z];
|
return tiles[x][y][z];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Region::SetSolid(int x, int y, bool b) {
|
bool Region::SetSolid(int x, int y, bool b) {
|
||||||
|
if (x < 0 || y < 0 || x >= REGION_WIDTH || y >= REGION_HEIGHT) {
|
||||||
|
throw(std::out_of_range("Region::SetSolid() argument out of range"));
|
||||||
|
}
|
||||||
return solid[x * REGION_WIDTH + y] = b;
|
return solid[x * REGION_WIDTH + y] = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Region::GetSolid(int x, int y) {
|
bool Region::GetSolid(int x, int y) {
|
||||||
|
if (x < 0 || y < 0 || x >= REGION_WIDTH || y >= REGION_HEIGHT) {
|
||||||
|
throw(std::out_of_range("Region::GetSolid() argument out of range"));
|
||||||
|
}
|
||||||
return solid[x * REGION_WIDTH + y];
|
return solid[x * REGION_WIDTH + y];
|
||||||
|
}
|
||||||
|
|
||||||
|
int Region::GetX() const {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Region::GetY() const {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::bitset<REGION_WIDTH*REGION_HEIGHT>* Region::GetSolidBitset() {
|
||||||
|
return &solid;
|
||||||
}
|
}
|
||||||
@@ -48,10 +48,10 @@ public:
|
|||||||
bool GetSolid(int x, int y);
|
bool GetSolid(int x, int y);
|
||||||
|
|
||||||
//accessors
|
//accessors
|
||||||
int GetX() const { return x; }
|
int GetX() const;
|
||||||
int GetY() const { return y; }
|
int GetY() const;
|
||||||
|
|
||||||
std::bitset<REGION_WIDTH*REGION_HEIGHT>* GetSolidBitset() { return &solid; }
|
std::bitset<REGION_WIDTH*REGION_HEIGHT>* GetSolidBitset();
|
||||||
private:
|
private:
|
||||||
const int x;
|
const int x;
|
||||||
const int y;
|
const int y;
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ static const luaL_Reg regionLib[] = {
|
|||||||
{"GetSolid",getSolid},
|
{"GetSolid",getSolid},
|
||||||
{"GetX",getX},
|
{"GetX",getX},
|
||||||
{"GetY",getY},
|
{"GetY",getY},
|
||||||
|
|
||||||
|
//the global macros
|
||||||
{"GetWidth",getWidth},
|
{"GetWidth",getWidth},
|
||||||
{"GetHeight",getHeight},
|
{"GetHeight",getHeight},
|
||||||
{"GetDepth",getDepth},
|
{"GetDepth",getDepth},
|
||||||
|
|||||||
@@ -22,13 +22,9 @@
|
|||||||
#ifndef REGIONAPI_HPP_
|
#ifndef REGIONAPI_HPP_
|
||||||
#define REGIONAPI_HPP_
|
#define REGIONAPI_HPP_
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#include "lua.hpp"
|
||||||
#include "lua/lua.hpp"
|
|
||||||
#else
|
|
||||||
#include "lua.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TORTUGA_REGION_NAME "region"
|
#define TORTUGA_REGION_API "region"
|
||||||
LUAMOD_API int openRegionAPI(lua_State* L);
|
LUAMOD_API int openRegionAPI(lua_State* L);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "region.hpp"
|
#include "region.hpp"
|
||||||
|
|
||||||
//DOCS: These glue functions simply wrap RegionPagerLua's methods
|
//DOCS: These glue functions simply wrap RegionPagerLua's methods
|
||||||
|
//NOTE: zero indexing is used here, but not in the region API
|
||||||
|
|
||||||
static int setTile(lua_State* L) {
|
static int setTile(lua_State* L) {
|
||||||
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
|
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
|
||||||
@@ -84,7 +85,22 @@ static int createRegion(lua_State* L) {
|
|||||||
|
|
||||||
static int unloadRegion(lua_State* L) {
|
static int unloadRegion(lua_State* L) {
|
||||||
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
|
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
|
||||||
pager->UnloadRegion(lua_tointeger(L, 2), lua_tointeger(L, 3));
|
|
||||||
|
//two argument types: coords & the region itself
|
||||||
|
switch(lua_type(L, 2)) {
|
||||||
|
case LUA_TNUMBER:
|
||||||
|
pager->UnloadIf([&](Region const& region) -> bool {
|
||||||
|
int x = lua_tointeger(L, 2);
|
||||||
|
int y = lua_tointeger(L, 3);
|
||||||
|
return region.GetX() == x && region.GetY() == y;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case LUA_TLIGHTUSERDATA:
|
||||||
|
pager->UnloadIf([&](Region const& region) -> bool {
|
||||||
|
return (®ion) == lua_touserdata(L, 2);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +132,13 @@ static int setOnUnload(lua_State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//debugging
|
||||||
|
static int containerSize(lua_State* L) {
|
||||||
|
RegionPagerLua* pager = static_cast<RegionPagerLua*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushinteger(L, pager->GetContainer()->size());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static const luaL_Reg regionPagerLib[] = {
|
static const luaL_Reg regionPagerLib[] = {
|
||||||
//curry
|
//curry
|
||||||
{"SetTile", setTile},
|
{"SetTile", setTile},
|
||||||
@@ -136,6 +159,9 @@ static const luaL_Reg regionPagerLib[] = {
|
|||||||
{"SetOnCreate",setOnCreate},
|
{"SetOnCreate",setOnCreate},
|
||||||
{"SetOnUnload",setOnUnload},
|
{"SetOnUnload",setOnUnload},
|
||||||
|
|
||||||
|
//debugging
|
||||||
|
{"ContainerSize", containerSize},
|
||||||
|
|
||||||
//sentinel
|
//sentinel
|
||||||
{nullptr, nullptr}
|
{nullptr, nullptr}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,13 +22,9 @@
|
|||||||
#ifndef REGIONPAGERAPI_HPP_
|
#ifndef REGIONPAGERAPI_HPP_
|
||||||
#define REGIONPAGERAPI_HPP_
|
#define REGIONPAGERAPI_HPP_
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#include "lua.hpp"
|
||||||
#include "lua/lua.hpp"
|
|
||||||
#else
|
|
||||||
#include "lua.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TORTUGA_REGION_PAGER_NAME "region_pager"
|
#define TORTUGA_REGION_PAGER_API "region_pager"
|
||||||
LUAMOD_API int openRegionPagerAPI(lua_State* L);
|
LUAMOD_API int openRegionPagerAPI(lua_State* L);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,6 +24,10 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
RegionPagerBase::~RegionPagerBase() {
|
||||||
|
UnloadAll();
|
||||||
|
};
|
||||||
|
|
||||||
Region::type_t RegionPagerBase::SetTile(int x, int y, int z, Region::type_t v) {
|
Region::type_t RegionPagerBase::SetTile(int x, int y, int z, Region::type_t v) {
|
||||||
Region* ptr = GetRegion(x, y);
|
Region* ptr = GetRegion(x, y);
|
||||||
return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v);
|
return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v);
|
||||||
@@ -88,12 +92,14 @@ Region* RegionPagerBase::CreateRegion(int x, int y) {
|
|||||||
return ®ionList.front();
|
return ®ionList.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionPagerBase::UnloadRegion(int x, int y) {
|
void RegionPagerBase::UnloadIf(std::function<bool(Region const&)> fn) {
|
||||||
regionList.remove_if([x, y](Region& region) -> bool {
|
regionList.remove_if(fn);
|
||||||
return region.GetX() == x && region.GetY() == y;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionPagerBase::UnloadAll() {
|
void RegionPagerBase::UnloadAll() {
|
||||||
regionList.clear();
|
regionList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<Region>* RegionPagerBase::GetContainer() {
|
||||||
|
return ®ionList;
|
||||||
}
|
}
|
||||||
@@ -24,12 +24,13 @@
|
|||||||
|
|
||||||
#include "region.hpp"
|
#include "region.hpp"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
class RegionPagerBase {
|
class RegionPagerBase {
|
||||||
public:
|
public:
|
||||||
RegionPagerBase() = default;
|
RegionPagerBase() = default;
|
||||||
virtual ~RegionPagerBase() { UnloadAll(); };
|
virtual ~RegionPagerBase();
|
||||||
|
|
||||||
//tile manipulation
|
//tile manipulation
|
||||||
virtual Region::type_t SetTile(int x, int y, int z, Region::type_t v);
|
virtual Region::type_t SetTile(int x, int y, int z, Region::type_t v);
|
||||||
@@ -47,12 +48,12 @@ public:
|
|||||||
virtual Region* LoadRegion(int x, int y);
|
virtual Region* LoadRegion(int x, int y);
|
||||||
virtual Region* SaveRegion(int x, int y);
|
virtual Region* SaveRegion(int x, int y);
|
||||||
virtual Region* CreateRegion(int x, int y);
|
virtual Region* CreateRegion(int x, int y);
|
||||||
virtual void UnloadRegion(int x, int y);
|
|
||||||
|
|
||||||
|
virtual void UnloadIf(std::function<bool(Region const&)> fn);
|
||||||
virtual void UnloadAll();
|
virtual void UnloadAll();
|
||||||
|
|
||||||
//accessors & mutators
|
//accessors & mutators
|
||||||
std::list<Region>* GetContainer() { return ®ionList; }
|
std::list<Region>* GetContainer();
|
||||||
protected:
|
protected:
|
||||||
std::list<Region> regionList;
|
std::list<Region> regionList;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,6 +23,9 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
//DOCS: Load, Save and Create fail unless the lua function has been set
|
||||||
|
//DOCS: UnloadIf and UnloadAll will still continue without the function set
|
||||||
|
|
||||||
RegionPagerLua::~RegionPagerLua() {
|
RegionPagerLua::~RegionPagerLua() {
|
||||||
//unload all regions
|
//unload all regions
|
||||||
UnloadAll();
|
UnloadAll();
|
||||||
@@ -130,23 +133,25 @@ Region* RegionPagerLua::CreateRegion(int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//no return
|
//no return
|
||||||
void RegionPagerLua::UnloadRegion(int x, int y) {
|
void RegionPagerLua::UnloadIf(std::function<bool(Region const&)> fn) {
|
||||||
//get the pager's function from the registry
|
//get the pager's function from the registry
|
||||||
lua_rawgeti(lua, LUA_REGISTRYINDEX, unloadRef);
|
lua_rawgeti(lua, LUA_REGISTRYINDEX, unloadRef);
|
||||||
|
|
||||||
//check if this function is available
|
//check if this function is available
|
||||||
if (lua_isnil(lua, -1)) {
|
if (lua_isnil(lua, -1)) {
|
||||||
lua_pop(lua, 1);
|
lua_pop(lua, 1);
|
||||||
|
//remove the regions anyway
|
||||||
|
regionList.remove_if(fn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//run each region through this lambda
|
//run each region through this lambda
|
||||||
regionList.remove_if([&](Region& region) -> bool {
|
regionList.remove_if([&](Region& region) -> bool {
|
||||||
if (region.GetX() == x && region.GetY() == y) {
|
if (fn(region)) {
|
||||||
|
|
||||||
//push a copy of the function onto the stack with the region
|
//push a copy of the function onto the stack with the region
|
||||||
lua_pushvalue(lua, -1);
|
lua_pushvalue(lua, -1);
|
||||||
lua_pushlightuserdata(lua, ®ion);
|
lua_pushlightuserdata(lua, static_cast<void*>(®ion));
|
||||||
|
|
||||||
//call the function, 1 arg, 0 return
|
//call the function, 1 arg, 0 return
|
||||||
if (lua_pcall(lua, 1, 0, 0) != LUA_OK) {
|
if (lua_pcall(lua, 1, 0, 0) != LUA_OK) {
|
||||||
@@ -171,6 +176,8 @@ void RegionPagerLua::UnloadAll() {
|
|||||||
//check if this function is available
|
//check if this function is available
|
||||||
if (lua_isnil(lua, -1)) {
|
if (lua_isnil(lua, -1)) {
|
||||||
lua_pop(lua, 1);
|
lua_pop(lua, 1);
|
||||||
|
//remove the regions anyway
|
||||||
|
regionList.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,12 +24,9 @@
|
|||||||
|
|
||||||
#include "region_pager_base.hpp"
|
#include "region_pager_base.hpp"
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#include "lua.hpp"
|
||||||
#include "lua/lua.hpp"
|
|
||||||
#else
|
|
||||||
#include "lua.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class RegionPagerLua : public RegionPagerBase {
|
class RegionPagerLua : public RegionPagerBase {
|
||||||
@@ -41,8 +38,8 @@ public:
|
|||||||
Region* LoadRegion(int x, int y) override;
|
Region* LoadRegion(int x, int y) override;
|
||||||
Region* SaveRegion(int x, int y) override;
|
Region* SaveRegion(int x, int y) override;
|
||||||
Region* CreateRegion(int x, int y) override;
|
Region* CreateRegion(int x, int y) override;
|
||||||
void UnloadRegion(int x, int y) override;
|
|
||||||
|
|
||||||
|
void UnloadIf(std::function<bool(Region const&)> fn) override;
|
||||||
void UnloadAll() override;
|
void UnloadAll() override;
|
||||||
|
|
||||||
//accessors & mutators
|
//accessors & mutators
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013-2015
|
|
||||||
*
|
|
||||||
* This software is provided 'as-is', without any express or implied
|
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
|
||||||
* arising from the use of this software.
|
|
||||||
*
|
|
||||||
* Permission is granted to anyone to use this software for any purpose,
|
|
||||||
* including commercial applications, and to alter it and redistribute it
|
|
||||||
* freely, subject to the following restrictions:
|
|
||||||
*
|
|
||||||
* 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
* claim that you wrote the original software. If you use this software
|
|
||||||
* in a product, an acknowledgment in the product documentation would be
|
|
||||||
* appreciated but is not required.
|
|
||||||
*
|
|
||||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
* misrepresented as being the original software.
|
|
||||||
*
|
|
||||||
* 3. This notice may not be removed or altered from any source
|
|
||||||
* distribution.
|
|
||||||
*/
|
|
||||||
#include "tile_sheet_api.hpp"
|
|
||||||
|
|
||||||
#include "tile_sheet.hpp"
|
|
||||||
|
|
||||||
static int load(lua_State* L) {
|
|
||||||
TileSheet* sheet = reinterpret_cast<TileSheet*>(lua_touserdata(L, 1));
|
|
||||||
sheet->Load(lua_tostring(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int unload(lua_State* L) {
|
|
||||||
TileSheet* sheet = reinterpret_cast<TileSheet*>(lua_touserdata(L, 1));
|
|
||||||
sheet->Unload();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getXCount(lua_State* L) {
|
|
||||||
TileSheet* sheet = reinterpret_cast<TileSheet*>(lua_touserdata(L, 1));
|
|
||||||
lua_pushinteger(L, sheet->GetXCount());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getYCount(lua_State* L) {
|
|
||||||
TileSheet* sheet = reinterpret_cast<TileSheet*>(lua_touserdata(L, 1));
|
|
||||||
lua_pushinteger(L, sheet->GetYCount());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getTileW(lua_State* L) {
|
|
||||||
TileSheet* sheet = reinterpret_cast<TileSheet*>(lua_touserdata(L, 1));
|
|
||||||
lua_pushinteger(L, sheet->GetTileW());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getTileH(lua_State* L) {
|
|
||||||
TileSheet* sheet = reinterpret_cast<TileSheet*>(lua_touserdata(L, 1));
|
|
||||||
lua_pushinteger(L, sheet->GetTileH());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const luaL_Reg tileSheetLib[] = {
|
|
||||||
{"Load",load},
|
|
||||||
{"Unload",unload},
|
|
||||||
{"GetXCount",getXCount},
|
|
||||||
{"GetYCount",getYCount},
|
|
||||||
{"GetTileW",getTileW},
|
|
||||||
{"GetTileH",getTileH},
|
|
||||||
{nullptr, nullptr}
|
|
||||||
};
|
|
||||||
|
|
||||||
LUAMOD_API int openTileSheetAPI(lua_State* L) {
|
|
||||||
luaL_newlib(L, tileSheetLib);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@@ -36,11 +36,18 @@ void serializeCharacter(void* buffer, CharacterPacket* packet) {
|
|||||||
|
|
||||||
//location
|
//location
|
||||||
serialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
serialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
||||||
|
|
||||||
serialCopy(&buffer, &packet->origin.x, sizeof(double));
|
serialCopy(&buffer, &packet->origin.x, sizeof(double));
|
||||||
serialCopy(&buffer, &packet->origin.y, sizeof(double));
|
serialCopy(&buffer, &packet->origin.y, sizeof(double));
|
||||||
|
|
||||||
serialCopy(&buffer, &packet->motion.x, sizeof(double));
|
serialCopy(&buffer, &packet->motion.x, sizeof(double));
|
||||||
serialCopy(&buffer, &packet->motion.y, sizeof(double));
|
serialCopy(&buffer, &packet->motion.y, sizeof(double));
|
||||||
|
|
||||||
|
serialCopy(&buffer, &packet->bounds.x, sizeof(int));
|
||||||
|
serialCopy(&buffer, &packet->bounds.y, sizeof(int));
|
||||||
|
serialCopy(&buffer, &packet->bounds.w, sizeof(int));
|
||||||
|
serialCopy(&buffer, &packet->bounds.h, sizeof(int));
|
||||||
|
|
||||||
//gameplay components: equipment, items, buffs, debuffs...
|
//gameplay components: equipment, items, buffs, debuffs...
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,10 +64,17 @@ void deserializeCharacter(void* buffer, CharacterPacket* packet) {
|
|||||||
|
|
||||||
//location
|
//location
|
||||||
deserialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
deserialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
||||||
|
|
||||||
deserialCopy(&buffer, &packet->origin.x, sizeof(double));
|
deserialCopy(&buffer, &packet->origin.x, sizeof(double));
|
||||||
deserialCopy(&buffer, &packet->origin.y, sizeof(double));
|
deserialCopy(&buffer, &packet->origin.y, sizeof(double));
|
||||||
|
|
||||||
deserialCopy(&buffer, &packet->motion.x, sizeof(double));
|
deserialCopy(&buffer, &packet->motion.x, sizeof(double));
|
||||||
deserialCopy(&buffer, &packet->motion.y, sizeof(double));
|
deserialCopy(&buffer, &packet->motion.y, sizeof(double));
|
||||||
|
|
||||||
|
deserialCopy(&buffer, &packet->bounds.x, sizeof(int));
|
||||||
|
deserialCopy(&buffer, &packet->bounds.y, sizeof(int));
|
||||||
|
deserialCopy(&buffer, &packet->bounds.w, sizeof(int));
|
||||||
|
deserialCopy(&buffer, &packet->bounds.h, sizeof(int));
|
||||||
|
|
||||||
//gameplay components: equipment, items, buffs, debuffs...
|
//gameplay components: equipment, items, buffs, debuffs...
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "serial_packet_base.hpp"
|
#include "serial_packet_base.hpp"
|
||||||
|
|
||||||
|
#include "bounding_box.hpp"
|
||||||
#include "vector2.hpp"
|
#include "vector2.hpp"
|
||||||
|
|
||||||
struct CharacterPacket : SerialPacketBase {
|
struct CharacterPacket : SerialPacketBase {
|
||||||
@@ -34,14 +35,12 @@ struct CharacterPacket : SerialPacketBase {
|
|||||||
|
|
||||||
//the owner
|
//the owner
|
||||||
int accountIndex;
|
int accountIndex;
|
||||||
//TODO: Authentication token?
|
|
||||||
|
|
||||||
//location
|
//location
|
||||||
int roomIndex;
|
int roomIndex;
|
||||||
Vector2 origin;
|
Vector2 origin;
|
||||||
Vector2 motion;
|
Vector2 motion;
|
||||||
|
BoundingBox bounds;
|
||||||
//gameplay components: equipment, items, buffs, debuffs...
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void serializeCharacter(void* buffer, CharacterPacket* packet);
|
void serializeCharacter(void* buffer, CharacterPacket* packet);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ struct ClientPacket : SerialPacketBase {
|
|||||||
int clientIndex;
|
int clientIndex;
|
||||||
int accountIndex;
|
int accountIndex;
|
||||||
char username[PACKET_STRING_SIZE];
|
char username[PACKET_STRING_SIZE];
|
||||||
|
//TODO: (3) password, auth token
|
||||||
};
|
};
|
||||||
|
|
||||||
void serializeClient(void* buffer, ClientPacket* packet);
|
void serializeClient(void* buffer, ClientPacket* packet);
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "monster_packet.hpp"
|
||||||
|
|
||||||
|
#include "serial_utility.hpp"
|
||||||
|
|
||||||
|
void serializeMonster(void* buffer, MonsterPacket* packet) {
|
||||||
|
serialCopy(&buffer, &packet->type, sizeof(SerialPacketType));
|
||||||
|
|
||||||
|
//identify the monster
|
||||||
|
serialCopy(&buffer, &packet->monsterIndex, sizeof(int));
|
||||||
|
serialCopy(&buffer, packet->handle, PACKET_STRING_SIZE);
|
||||||
|
serialCopy(&buffer, packet->avatar, PACKET_STRING_SIZE);
|
||||||
|
|
||||||
|
//bounds
|
||||||
|
serialCopy(&buffer, &packet->bounds.x, sizeof(int));
|
||||||
|
serialCopy(&buffer, &packet->bounds.y, sizeof(int));
|
||||||
|
serialCopy(&buffer, &packet->bounds.w, sizeof(int));
|
||||||
|
serialCopy(&buffer, &packet->bounds.h, sizeof(int));
|
||||||
|
|
||||||
|
|
||||||
|
//location
|
||||||
|
serialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
||||||
|
serialCopy(&buffer, &packet->origin.x, sizeof(double));
|
||||||
|
serialCopy(&buffer, &packet->origin.y, sizeof(double));
|
||||||
|
serialCopy(&buffer, &packet->motion.x, sizeof(double));
|
||||||
|
serialCopy(&buffer, &packet->motion.y, sizeof(double));
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserializeMonster(void* buffer, MonsterPacket* packet) {
|
||||||
|
deserialCopy(&buffer, &packet->type, sizeof(SerialPacketType));
|
||||||
|
|
||||||
|
//identify the monster
|
||||||
|
deserialCopy(&buffer, &packet->monsterIndex, sizeof(int));
|
||||||
|
deserialCopy(&buffer, packet->handle, PACKET_STRING_SIZE);
|
||||||
|
deserialCopy(&buffer, packet->avatar, PACKET_STRING_SIZE);
|
||||||
|
|
||||||
|
//bounds
|
||||||
|
deserialCopy(&buffer, &packet->bounds.x, sizeof(int));
|
||||||
|
deserialCopy(&buffer, &packet->bounds.y, sizeof(int));
|
||||||
|
deserialCopy(&buffer, &packet->bounds.w, sizeof(int));
|
||||||
|
deserialCopy(&buffer, &packet->bounds.h, sizeof(int));
|
||||||
|
|
||||||
|
|
||||||
|
//location
|
||||||
|
deserialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
||||||
|
deserialCopy(&buffer, &packet->origin.x, sizeof(double));
|
||||||
|
deserialCopy(&buffer, &packet->origin.y, sizeof(double));
|
||||||
|
deserialCopy(&buffer, &packet->motion.x, sizeof(double));
|
||||||
|
deserialCopy(&buffer, &packet->motion.y, sizeof(double));
|
||||||
|
}
|
||||||
@@ -19,31 +19,28 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef DOORDATA_HPP_
|
#ifndef MONSTERPACKET_HPP_
|
||||||
#define DOORDATA_HPP_
|
#define MONSTERPACKET_HPP_
|
||||||
|
|
||||||
#include "entity.hpp"
|
#include "serial_packet_base.hpp"
|
||||||
|
|
||||||
|
#include "bounding_box.hpp"
|
||||||
#include "vector2.hpp"
|
#include "vector2.hpp"
|
||||||
|
|
||||||
#include <string>
|
struct MonsterPacket : SerialPacketBase {
|
||||||
|
//identify the monster
|
||||||
|
int monsterIndex;
|
||||||
|
char handle[PACKET_STRING_SIZE];
|
||||||
|
char avatar[PACKET_STRING_SIZE];
|
||||||
|
BoundingBox bounds;
|
||||||
|
|
||||||
class DoorData: public Entity {
|
//location
|
||||||
public:
|
int roomIndex;
|
||||||
DoorData() = default;
|
Vector2 origin;
|
||||||
~DoorData() = default;
|
Vector2 motion;
|
||||||
|
|
||||||
//accessors & mutators
|
|
||||||
std::string SetRoomName(std::string);
|
|
||||||
Vector2 SetDestPosition(Vector2);
|
|
||||||
|
|
||||||
std::string GetRoomName();
|
|
||||||
Vector2 GetDestPosition();
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class DoorManager;
|
|
||||||
|
|
||||||
std::string roomName;
|
|
||||||
Vector2 destPosition;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void serializeMonster(void* buffer, MonsterPacket* packet);
|
||||||
|
void deserializeMonster(void* buffer, MonsterPacket* packet);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -29,6 +29,12 @@ void serializeText(void* buffer, TextPacket* packet) {
|
|||||||
//content
|
//content
|
||||||
serialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
|
serialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
|
||||||
serialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
|
serialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
|
||||||
|
|
||||||
|
//location
|
||||||
|
serialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
||||||
|
serialCopy(&buffer, &packet->origin.x, sizeof(double));
|
||||||
|
serialCopy(&buffer, &packet->origin.y, sizeof(double));
|
||||||
|
serialCopy(&buffer, &packet->range, sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
void deserializeText(void* buffer, TextPacket* packet) {
|
void deserializeText(void* buffer, TextPacket* packet) {
|
||||||
@@ -37,4 +43,10 @@ void deserializeText(void* buffer, TextPacket* packet) {
|
|||||||
//content
|
//content
|
||||||
deserialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
|
deserialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
|
||||||
deserialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
|
deserialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
|
||||||
|
|
||||||
|
//location
|
||||||
|
deserialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
||||||
|
deserialCopy(&buffer, &packet->origin.x, sizeof(double));
|
||||||
|
deserialCopy(&buffer, &packet->origin.y, sizeof(double));
|
||||||
|
deserialCopy(&buffer, &packet->range, sizeof(int));
|
||||||
}
|
}
|
||||||
@@ -24,9 +24,14 @@
|
|||||||
|
|
||||||
#include "serial_packet_base.hpp"
|
#include "serial_packet_base.hpp"
|
||||||
|
|
||||||
|
#include "vector2.hpp"
|
||||||
|
|
||||||
struct TextPacket : SerialPacketBase {
|
struct TextPacket : SerialPacketBase {
|
||||||
char name[PACKET_STRING_SIZE];
|
char name[PACKET_STRING_SIZE];
|
||||||
char text[PACKET_STRING_SIZE];
|
char text[PACKET_STRING_SIZE];
|
||||||
|
int roomIndex;
|
||||||
|
Vector2 origin;
|
||||||
|
int range;
|
||||||
};
|
};
|
||||||
|
|
||||||
void serializeText(void* buffer, TextPacket* packet);
|
void serializeText(void* buffer, TextPacket* packet);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "serial_packet_base.hpp"
|
#include "serial_packet_base.hpp"
|
||||||
#include "character_packet.hpp"
|
#include "character_packet.hpp"
|
||||||
#include "client_packet.hpp"
|
#include "client_packet.hpp"
|
||||||
|
#include "monster_packet.hpp"
|
||||||
#include "region_packet.hpp"
|
#include "region_packet.hpp"
|
||||||
#include "server_packet.hpp"
|
#include "server_packet.hpp"
|
||||||
#include "text_packet.hpp"
|
#include "text_packet.hpp"
|
||||||
@@ -33,14 +34,15 @@
|
|||||||
typedef SerialPacketBase SerialPacket;
|
typedef SerialPacketBase SerialPacket;
|
||||||
|
|
||||||
//DOCS: NETWORK_VERSION is used to discern compatible servers and clients
|
//DOCS: NETWORK_VERSION is used to discern compatible servers and clients
|
||||||
constexpr int NETWORK_VERSION = 20141227;
|
constexpr int NETWORK_VERSION = 20150304;
|
||||||
|
|
||||||
union MaxPacket {
|
union MaxPacket {
|
||||||
CharacterPacket a;
|
CharacterPacket a;
|
||||||
ClientPacket b;
|
ClientPacket b;
|
||||||
RegionPacket c;
|
MonsterPacket c;
|
||||||
ServerPacket d;
|
RegionPacket d;
|
||||||
TextPacket e;
|
ServerPacket e;
|
||||||
|
TextPacket f;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr int MAX_PACKET_SIZE = sizeof(MaxPacket);
|
constexpr int MAX_PACKET_SIZE = sizeof(MaxPacket);
|
||||||
|
|||||||
@@ -25,107 +25,163 @@
|
|||||||
/* DOCS: The headers indicate what packet type is used for each message
|
/* DOCS: The headers indicate what packet type is used for each message
|
||||||
* different messages under the same header will carry different amounts of
|
* different messages under the same header will carry different amounts of
|
||||||
* valid data, but it will still be carried in that packet's format.
|
* valid data, but it will still be carried in that packet's format.
|
||||||
|
* FORMAT_* is for internal use, deviding the different format bounds.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//TODO: This needs to be smoothed out
|
|
||||||
enum class SerialPacketType {
|
enum class SerialPacketType {
|
||||||
//default: there is something wrong
|
//default: there is something wrong
|
||||||
NONE = 0,
|
NONE,
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//ServerPacket
|
//ServerPacket
|
||||||
// name, player count, version
|
// name, player count, version
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
|
FORMAT_SERVER,
|
||||||
|
|
||||||
//heartbeat
|
//heartbeat
|
||||||
PING = 1,
|
PING,
|
||||||
PONG = 2,
|
PONG,
|
||||||
|
|
||||||
//Used for finding available servers
|
//Used for finding available servers
|
||||||
BROADCAST_REQUEST = 3,
|
BROADCAST_REQUEST,
|
||||||
BROADCAST_RESPONSE = 4,
|
BROADCAST_RESPONSE,
|
||||||
|
|
||||||
|
FORMAT_END_SERVER,
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//ClientPacket
|
//ClientPacket
|
||||||
// client index, account index, username
|
// client index, account index, username
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
|
FORMAT_CLIENT,
|
||||||
|
|
||||||
//Connecting to a server as a client
|
//Connecting to a server as a client
|
||||||
JOIN_REQUEST = 5,
|
JOIN_REQUEST,
|
||||||
JOIN_RESPONSE = 6,
|
JOIN_RESPONSE,
|
||||||
|
|
||||||
//disconnect from the server
|
//disconnect from the server
|
||||||
DISCONNECT_REQUEST = 7,
|
DISCONNECT_REQUEST,
|
||||||
DISCONNECT_RESPONSE = 8,
|
DISCONNECT_RESPONSE,
|
||||||
DISCONNECT_FORCED = 9,
|
ADMIN_DISCONNECT_FORCED,
|
||||||
|
|
||||||
//load the account
|
//load the account
|
||||||
LOGIN_REQUEST = 10,
|
LOGIN_REQUEST,
|
||||||
LOGIN_RESPONSE = 11,
|
LOGIN_RESPONSE,
|
||||||
|
|
||||||
//unload the account
|
//unload the account
|
||||||
LOGOUT_REQUEST = 12,
|
LOGOUT_REQUEST,
|
||||||
LOGOUT_RESPONSE = 13,
|
LOGOUT_RESPONSE,
|
||||||
|
|
||||||
//shut down the server
|
//shut down the server
|
||||||
SHUTDOWN_REQUEST = 14,
|
ADMIN_SHUTDOWN_REQUEST,
|
||||||
|
|
||||||
|
FORMAT_END_CLIENT,
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//RegionPacket
|
//RegionPacket
|
||||||
// room index, x, y, raw data
|
// room index, x, y, raw data
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
|
FORMAT_REGION,
|
||||||
|
|
||||||
//map data
|
//map data
|
||||||
REGION_REQUEST = 15, //NOTE: technically a query
|
REGION_REQUEST,
|
||||||
REGION_CONTENT = 16,
|
REGION_CONTENT,
|
||||||
|
|
||||||
|
FORMAT_END_REGION,
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//CharacterPacket
|
//CharacterPacket
|
||||||
// character index,
|
// character index,
|
||||||
// handle, avatar,
|
// handle, avatar,
|
||||||
// account index (owner),
|
// account index (owner),
|
||||||
// room index, origin, motion,
|
// room index, origin, motion
|
||||||
// statistics
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
|
FORMAT_CHARACTER,
|
||||||
|
|
||||||
|
//full data update
|
||||||
|
CHARACTER_UPDATE,
|
||||||
|
|
||||||
//character management
|
//character management
|
||||||
CHARACTER_CREATE = 17,
|
CHARACTER_CREATE,
|
||||||
CHARACTER_DELETE = 18,
|
CHARACTER_DELETE,
|
||||||
CHARACTER_LOAD = 19,
|
CHARACTER_LOAD,
|
||||||
CHARACTER_UNLOAD = 20,
|
CHARACTER_UNLOAD,
|
||||||
|
|
||||||
//find out info from the server
|
//find out info from the server
|
||||||
QUERY_CHARACTER_EXISTS = 21,
|
QUERY_CHARACTER_EXISTS,
|
||||||
QUERY_CHARACTER_STATS = 22,
|
QUERY_CHARACTER_STATS,
|
||||||
QUERY_CHARACTER_LOCATION = 23,
|
QUERY_CHARACTER_LOCATION,
|
||||||
|
|
||||||
//set the info in the server
|
//actions taken
|
||||||
CHARACTER_SET_ROOM = 24,
|
CHARACTER_MOVEMENT,
|
||||||
CHARACTER_SET_ORIGIN = 25,
|
CHARACTER_ATTACK,
|
||||||
CHARACTER_SET_MOTION = 26,
|
CHARACTER_DAMAGE,
|
||||||
|
|
||||||
//TODO: enemy management
|
//admin control
|
||||||
|
// ADMIN_SET_CHARACTER_ORIGIN,
|
||||||
|
|
||||||
|
FORMAT_END_CHARACTER,
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//MonsterPacket
|
||||||
|
// monster index,
|
||||||
|
// handle, avatar
|
||||||
|
// bounds
|
||||||
|
// room index, origin, motion
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
FORMAT_MONSTER,
|
||||||
|
|
||||||
|
//full data update
|
||||||
|
MONSTER_UPDATE,
|
||||||
|
|
||||||
|
//character management
|
||||||
|
MONSTER_CREATE,
|
||||||
|
MONSTER_DELETE,
|
||||||
|
|
||||||
|
//find out info from the server
|
||||||
|
QUERY_MONSTER_EXISTS,
|
||||||
|
QUERY_MONSTER_STATS,
|
||||||
|
QUERY_MONSTER_LOCATION,
|
||||||
|
|
||||||
|
//actions taken
|
||||||
|
MONSTER_MOVEMENT,
|
||||||
|
MONSTER_ATTACK,
|
||||||
|
MONSTER_DAMAGE,
|
||||||
|
|
||||||
|
FORMAT_END_MONSTER,
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//TextPacket
|
//TextPacket
|
||||||
// name, text
|
// name, text
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
|
FORMAT_TEXT,
|
||||||
|
|
||||||
//general speech
|
//general speech
|
||||||
TEXT_BROADCAST = 27,
|
TEXT_BROADCAST,
|
||||||
|
TEXT_SPEECH,
|
||||||
|
TEXT_WHISPER,
|
||||||
|
|
||||||
//rejection/error messages
|
//rejection/error messages
|
||||||
JOIN_REJECTION = 28,
|
JOIN_REJECTION,
|
||||||
LOGIN_REJECTION = 29,
|
LOGIN_REJECTION,
|
||||||
REGION_REJECTION = 30,
|
REGION_REJECTION,
|
||||||
CHARACTER_REJECTION = 31,
|
CHARACTER_REJECTION,
|
||||||
SHUTDOWN_REJECTION = 32,
|
MONSTER_REJECTION,
|
||||||
|
SHUTDOWN_REJECTION,
|
||||||
|
QUERY_REJECTION,
|
||||||
|
|
||||||
|
FORMAT_END_TEXT,
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//not used
|
//not used
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
LAST = 33
|
LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -24,12 +24,16 @@
|
|||||||
//packet types
|
//packet types
|
||||||
#include "character_packet.hpp"
|
#include "character_packet.hpp"
|
||||||
#include "client_packet.hpp"
|
#include "client_packet.hpp"
|
||||||
|
#include "monster_packet.hpp"
|
||||||
#include "region_packet.hpp"
|
#include "region_packet.hpp"
|
||||||
#include "server_packet.hpp"
|
#include "server_packet.hpp"
|
||||||
#include "text_packet.hpp"
|
#include "text_packet.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
//macros
|
||||||
|
#define BOUNDS(type, lower, upper) ((type) > (lower) && (type) < (upper))
|
||||||
|
|
||||||
//raw memory copy
|
//raw memory copy
|
||||||
void serialCopy(void** buffer, void* data, int size) {
|
void serialCopy(void** buffer, void* data, int size) {
|
||||||
memcpy(*buffer, data, size);
|
memcpy(*buffer, data, size);
|
||||||
@@ -45,49 +49,28 @@ void deserialCopy(void** buffer, void* data, int size) {
|
|||||||
|
|
||||||
//main switch functions
|
//main switch functions
|
||||||
void serializePacket(void* buffer, SerialPacketBase* packet) {
|
void serializePacket(void* buffer, SerialPacketBase* packet) {
|
||||||
switch(packet->type) {
|
if (BOUNDS(packet->type, SerialPacketType::FORMAT_SERVER, SerialPacketType::FORMAT_END_SERVER)) {
|
||||||
case SerialPacketType::PING:
|
serializeServer(buffer, static_cast<ServerPacket*>(packet));
|
||||||
case SerialPacketType::PONG:
|
}
|
||||||
case SerialPacketType::BROADCAST_REQUEST:
|
|
||||||
case SerialPacketType::BROADCAST_RESPONSE:
|
if (BOUNDS(packet->type, SerialPacketType::FORMAT_CLIENT, SerialPacketType::FORMAT_END_CLIENT)) {
|
||||||
serializeServer(buffer, static_cast<ServerPacket*>(packet));
|
serializeClient(buffer, static_cast<ClientPacket*>(packet));
|
||||||
break;
|
}
|
||||||
case SerialPacketType::JOIN_REQUEST:
|
|
||||||
case SerialPacketType::JOIN_RESPONSE:
|
if (BOUNDS(packet->type, SerialPacketType::FORMAT_REGION, SerialPacketType::FORMAT_END_REGION)) {
|
||||||
case SerialPacketType::DISCONNECT_REQUEST:
|
serializeRegion(buffer, static_cast<RegionPacket*>(packet));
|
||||||
case SerialPacketType::DISCONNECT_RESPONSE:
|
}
|
||||||
case SerialPacketType::DISCONNECT_FORCED:
|
|
||||||
case SerialPacketType::LOGIN_REQUEST:
|
if (BOUNDS(packet->type, SerialPacketType::FORMAT_CHARACTER, SerialPacketType::FORMAT_END_CHARACTER)) {
|
||||||
case SerialPacketType::LOGIN_RESPONSE:
|
serializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
||||||
case SerialPacketType::LOGOUT_REQUEST:
|
}
|
||||||
case SerialPacketType::LOGOUT_RESPONSE:
|
|
||||||
case SerialPacketType::SHUTDOWN_REQUEST:
|
if (BOUNDS(packet->type, SerialPacketType::FORMAT_MONSTER, SerialPacketType::FORMAT_END_MONSTER)) {
|
||||||
serializeClient(buffer, static_cast<ClientPacket*>(packet));
|
serializeMonster(buffer, static_cast<MonsterPacket*>(packet));
|
||||||
break;
|
}
|
||||||
case SerialPacketType::REGION_REQUEST:
|
|
||||||
case SerialPacketType::REGION_CONTENT:
|
if (BOUNDS(packet->type, SerialPacketType::FORMAT_TEXT, SerialPacketType::FORMAT_END_TEXT)) {
|
||||||
serializeRegion(buffer, static_cast<RegionPacket*>(packet));
|
serializeText(buffer, static_cast<TextPacket*>(packet));
|
||||||
break;
|
|
||||||
case SerialPacketType::CHARACTER_CREATE:
|
|
||||||
case SerialPacketType::CHARACTER_DELETE:
|
|
||||||
case SerialPacketType::CHARACTER_LOAD:
|
|
||||||
case SerialPacketType::CHARACTER_UNLOAD:
|
|
||||||
case SerialPacketType::QUERY_CHARACTER_EXISTS:
|
|
||||||
case SerialPacketType::QUERY_CHARACTER_STATS:
|
|
||||||
case SerialPacketType::QUERY_CHARACTER_LOCATION:
|
|
||||||
case SerialPacketType::CHARACTER_SET_ROOM:
|
|
||||||
case SerialPacketType::CHARACTER_SET_ORIGIN:
|
|
||||||
case SerialPacketType::CHARACTER_SET_MOTION:
|
|
||||||
serializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
|
||||||
break;
|
|
||||||
case SerialPacketType::TEXT_BROADCAST:
|
|
||||||
case SerialPacketType::JOIN_REJECTION:
|
|
||||||
case SerialPacketType::LOGIN_REJECTION:
|
|
||||||
case SerialPacketType::REGION_REJECTION:
|
|
||||||
case SerialPacketType::CHARACTER_REJECTION:
|
|
||||||
case SerialPacketType::SHUTDOWN_REJECTION:
|
|
||||||
serializeText(buffer, static_cast<TextPacket*>(packet));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,48 +79,27 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) {
|
|||||||
SerialPacketType type;
|
SerialPacketType type;
|
||||||
memcpy(&type, buffer, sizeof(SerialPacketType));
|
memcpy(&type, buffer, sizeof(SerialPacketType));
|
||||||
|
|
||||||
switch(type) {
|
if (BOUNDS(type, SerialPacketType::FORMAT_SERVER, SerialPacketType::FORMAT_END_SERVER)) {
|
||||||
case SerialPacketType::PING:
|
deserializeServer(buffer, static_cast<ServerPacket*>(packet));
|
||||||
case SerialPacketType::PONG:
|
}
|
||||||
case SerialPacketType::BROADCAST_REQUEST:
|
|
||||||
case SerialPacketType::BROADCAST_RESPONSE:
|
if (BOUNDS(type, SerialPacketType::FORMAT_CLIENT, SerialPacketType::FORMAT_END_CLIENT)) {
|
||||||
deserializeServer(buffer, static_cast<ServerPacket*>(packet));
|
deserializeClient(buffer, static_cast<ClientPacket*>(packet));
|
||||||
break;
|
}
|
||||||
case SerialPacketType::JOIN_REQUEST:
|
|
||||||
case SerialPacketType::JOIN_RESPONSE:
|
if (BOUNDS(type, SerialPacketType::FORMAT_REGION, SerialPacketType::FORMAT_END_REGION)) {
|
||||||
case SerialPacketType::DISCONNECT_REQUEST:
|
deserializeRegion(buffer, static_cast<RegionPacket*>(packet));
|
||||||
case SerialPacketType::DISCONNECT_RESPONSE:
|
}
|
||||||
case SerialPacketType::DISCONNECT_FORCED:
|
|
||||||
case SerialPacketType::LOGIN_REQUEST:
|
if (BOUNDS(type, SerialPacketType::FORMAT_CHARACTER, SerialPacketType::FORMAT_END_CHARACTER)) {
|
||||||
case SerialPacketType::LOGIN_RESPONSE:
|
deserializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
||||||
case SerialPacketType::LOGOUT_REQUEST:
|
}
|
||||||
case SerialPacketType::LOGOUT_RESPONSE:
|
|
||||||
case SerialPacketType::SHUTDOWN_REQUEST:
|
if (BOUNDS(type, SerialPacketType::FORMAT_MONSTER, SerialPacketType::FORMAT_END_MONSTER)) {
|
||||||
deserializeClient(buffer, static_cast<ClientPacket*>(packet));
|
deserializeMonster(buffer, static_cast<MonsterPacket*>(packet));
|
||||||
break;
|
}
|
||||||
case SerialPacketType::REGION_REQUEST:
|
|
||||||
case SerialPacketType::REGION_CONTENT:
|
if (BOUNDS(type, SerialPacketType::FORMAT_TEXT, SerialPacketType::FORMAT_END_TEXT)) {
|
||||||
deserializeRegion(buffer, static_cast<RegionPacket*>(packet));
|
deserializeText(buffer, static_cast<TextPacket*>(packet));
|
||||||
break;
|
|
||||||
case SerialPacketType::CHARACTER_CREATE:
|
|
||||||
case SerialPacketType::CHARACTER_DELETE:
|
|
||||||
case SerialPacketType::CHARACTER_LOAD:
|
|
||||||
case SerialPacketType::CHARACTER_UNLOAD:
|
|
||||||
case SerialPacketType::QUERY_CHARACTER_EXISTS:
|
|
||||||
case SerialPacketType::QUERY_CHARACTER_STATS:
|
|
||||||
case SerialPacketType::QUERY_CHARACTER_LOCATION:
|
|
||||||
case SerialPacketType::CHARACTER_SET_ROOM:
|
|
||||||
case SerialPacketType::CHARACTER_SET_ORIGIN:
|
|
||||||
case SerialPacketType::CHARACTER_SET_MOTION:
|
|
||||||
deserializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
|
||||||
break;
|
|
||||||
case SerialPacketType::TEXT_BROADCAST:
|
|
||||||
case SerialPacketType::JOIN_REJECTION:
|
|
||||||
case SerialPacketType::LOGIN_REJECTION:
|
|
||||||
case SerialPacketType::REGION_REJECTION:
|
|
||||||
case SerialPacketType::CHARACTER_REJECTION:
|
|
||||||
case SerialPacketType::SHUTDOWN_REJECTION:
|
|
||||||
deserializeText(buffer, static_cast<TextPacket*>(packet));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
//NOTE: memset() is used before sending a packet to remove old data; you don't want to send sensitive data over the network
|
//DOCS: memset() is used before sending a packet to remove old data; you don't want to send sensitive data over the network
|
||||||
//NOTE: don't confuse SerialPacketBase with UDPpacket
|
//NOTE: don't confuse SerialPacketBase with UDPpacket
|
||||||
|
|
||||||
void UDPNetworkUtility::Open(int port) {
|
void UDPNetworkUtility::Open(int port) {
|
||||||
@@ -140,7 +140,6 @@ int UDPNetworkUtility::SendToAllChannels(void* data, int len) {
|
|||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: put a void* and int* parameter list here
|
|
||||||
int UDPNetworkUtility::Receive() {
|
int UDPNetworkUtility::Receive() {
|
||||||
memset(packet->data, 0, packet->maxlen);
|
memset(packet->data, 0, packet->maxlen);
|
||||||
int ret = SDLNet_UDP_Recv(socket, packet);
|
int ret = SDLNet_UDP_Recv(socket, packet);
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "ip_operators.hpp"
|
||||||
|
|
||||||
|
bool operator==(IPaddress lhs, IPaddress rhs) {
|
||||||
|
return lhs.host == rhs.host && lhs.port == rhs.port;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(IPaddress lhs, IPaddress rhs) {
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
@@ -19,16 +19,13 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef UTILITY_HPP_
|
#ifndef IPOPERATORS_HPP_
|
||||||
#define UTILITY_HPP_
|
#define IPOPERATORS_HPP_
|
||||||
|
|
||||||
#include <string>
|
#include "SDL/SDL_net.h"
|
||||||
|
|
||||||
std::string truncatePath(std::string pathname);
|
//these should've come standard
|
||||||
|
bool operator==(IPaddress lhs, IPaddress rhs);
|
||||||
|
bool operator!=(IPaddress lhs, IPaddress rhs);
|
||||||
|
|
||||||
//fixing known bugs in g++
|
#endif
|
||||||
std::string to_string_custom(int i);
|
|
||||||
|
|
||||||
int to_integer_custom(std::string);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013-2015
|
|
||||||
*
|
|
||||||
* This software is provided 'as-is', without any express or implied
|
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
|
||||||
* arising from the use of this software.
|
|
||||||
*
|
|
||||||
* Permission is granted to anyone to use this software for any purpose,
|
|
||||||
* including commercial applications, and to alter it and redistribute it
|
|
||||||
* freely, subject to the following restrictions:
|
|
||||||
*
|
|
||||||
* 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
* claim that you wrote the original software. If you use this software
|
|
||||||
* in a product, an acknowledgment in the product documentation would be
|
|
||||||
* appreciated but is not required.
|
|
||||||
*
|
|
||||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
* misrepresented as being the original software.
|
|
||||||
*
|
|
||||||
* 3. This notice may not be removed or altered from any source
|
|
||||||
* distribution.
|
|
||||||
*/
|
|
||||||
#include "utility.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
std::string truncatePath(std::string pathname) {
|
|
||||||
return std::string(
|
|
||||||
std::find_if(
|
|
||||||
pathname.rbegin(),
|
|
||||||
pathname.rend(),
|
|
||||||
[](char ch) -> bool {
|
|
||||||
//windows & unix tested
|
|
||||||
return ch == '/' || ch == '\\';
|
|
||||||
}).base(),
|
|
||||||
pathname.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string to_string_custom(int i) {
|
|
||||||
char buffer[20];
|
|
||||||
snprintf(buffer, 20, "%d", i);
|
|
||||||
return std::string(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
int to_integer_custom(std::string s) {
|
|
||||||
int ret = 0;
|
|
||||||
sscanf(s.c_str(), "%d", &ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
+1
-1
@@ -2,7 +2,7 @@ Future versions (to be determined) may be released under a modified version of t
|
|||||||
|
|
||||||
The current version of Tortuga is released under the zlib license.
|
The current version of Tortuga is released under the zlib license.
|
||||||
|
|
||||||
Copyright (c) 2013, 2014 Kayne Ruse
|
Copyright (c) 2013-2015 Kayne Ruse
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,10 @@ Both a game server and game client are included in this package.
|
|||||||
Instructions For Setup
|
Instructions For Setup
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
1. To create a server, simply run server.exe.
|
1. To create a server, simply run server.exe
|
||||||
2. To join that server, run client.exe with config settings not already in use.
|
(a public server is provided by default)
|
||||||
(Note: This process will be streamlined later).
|
2. To join a server, your player information must be input into rsc/config.cfg
|
||||||
|
(NOTE: This process will be streamlined later)
|
||||||
3. To change the config settings, open rsc/config.cfg
|
3. To change the config settings, open rsc/config.cfg
|
||||||
4. These settings must be unique for each player:
|
4. These settings must be unique for each player:
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ Instructions For Setup
|
|||||||
* client.avatar = elliot2.bmp #male
|
* client.avatar = elliot2.bmp #male
|
||||||
* client.avatar = coa2.bmp #female
|
* client.avatar = coa2.bmp #female
|
||||||
|
|
||||||
6. When you've correctly set these values (good luck), select 'Start' from the
|
6. When you've correctly set these values, run client.exe, and select 'Start'
|
||||||
main menu; this displays the list of available servers.
|
from the main menu; this displays the list of available servers.
|
||||||
7. Select the name of your server (default is 'local') and select 'Join'.
|
7. Select the name of a server (default is 'Public') and select 'Join'.
|
||||||
8. Welcome to Tortuga, enjoy your stay.
|
8. Welcome to Tortuga, enjoy your stay.
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
#for use on Windows:
|
#Windows 7:
|
||||||
|
|
||||||
#MKDIR=mkdir
|
|
||||||
#RM=del /y
|
#RM=del /y
|
||||||
|
|
||||||
|
#Windows 8.1:
|
||||||
|
#RM=del /S
|
||||||
|
|
||||||
OUTDIR=out
|
OUTDIR=out
|
||||||
|
|
||||||
all: $(OUTDIR)
|
all: $(OUTDIR)
|
||||||
@@ -19,7 +20,7 @@ release: clean all package
|
|||||||
#For use on my machine ONLY
|
#For use on my machine ONLY
|
||||||
package:
|
package:
|
||||||
rar a -r -ep Tortuga.rar $(OUTDIR)/*.exe $(OUTDIR)/*.dll
|
rar a -r -ep Tortuga.rar $(OUTDIR)/*.exe $(OUTDIR)/*.dll
|
||||||
rar a -r Tortuga.rar rsc/* copyright.txt README.txt
|
rar a -r Tortuga.rar rsc/* copyright.txt instructions.txt
|
||||||
|
|
||||||
$(OUTDIR):
|
$(OUTDIR):
|
||||||
mkdir $(OUTDIR)
|
mkdir $(OUTDIR)
|
||||||
|
|||||||
+2
-2
@@ -12,8 +12,8 @@ server.dbname = database.db
|
|||||||
#client.screen.h = 600
|
#client.screen.h = 600
|
||||||
client.screen.f = false
|
client.screen.f = false
|
||||||
|
|
||||||
client.username = Kayne Ruse
|
client.username = username
|
||||||
client.handle = Ratstail91
|
client.handle = handle
|
||||||
client.avatar = elliot2.bmp
|
client.avatar = elliot2.bmp
|
||||||
|
|
||||||
#directories
|
#directories
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
local doorUtility = {}
|
||||||
|
|
||||||
|
roomAPI = require("room")
|
||||||
|
regionPagerAPI = require("region_pager")
|
||||||
|
|
||||||
|
triggerAPI = require("trigger")
|
||||||
|
triggerManagerAPI = require("trigger_manager")
|
||||||
|
|
||||||
|
entityAPI = require("entity")
|
||||||
|
characterAPI = require("character")
|
||||||
|
|
||||||
|
networkAPI = require("network")
|
||||||
|
|
||||||
|
function doorUtility.createTrigger(handle, room, x, y, script)
|
||||||
|
local pager = roomAPI.GetPager(room)
|
||||||
|
|
||||||
|
--place the indicator tile
|
||||||
|
regionPagerAPI.SetTile(pager, x / 32, y / 32, 0, mapMaker.dirt)
|
||||||
|
regionPagerAPI.SetTile(pager, x / 32, y / 32, 1, mapMaker.blank)
|
||||||
|
regionPagerAPI.SetTile(pager, x / 32, y / 32, 2, mapMaker.blank)
|
||||||
|
|
||||||
|
--create the trigger object
|
||||||
|
triggerManagerAPI.Create(
|
||||||
|
roomAPI.GetTriggerMgr(room), handle, x, y,
|
||||||
|
0, 0, 32, 32, --size of the tiles
|
||||||
|
script
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
function doorUtility.createDoorPair(handle, roomOne, Xone, Yone, roomTwo, Xtwo, Ytwo)
|
||||||
|
--create the scripts
|
||||||
|
local function scriptOne(entity)
|
||||||
|
if entityAPI.GetType(entity) ~= "character" then return end
|
||||||
|
|
||||||
|
--move the character
|
||||||
|
characterAPI.SetRoom(entity, roomTwo)
|
||||||
|
characterAPI.SetOrigin(entity, Xtwo, Ytwo-16)
|
||||||
|
networkAPI.PumpCharacterUpdate(entity)
|
||||||
|
|
||||||
|
--disable the other trigger
|
||||||
|
local triggerTwo = triggerManagerAPI.GetTrigger(roomAPI.GetTriggerMgr(roomTwo), handle)
|
||||||
|
triggerAPI.PushExclusionEntity(triggerTwo, entity)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function scriptTwo(entity)
|
||||||
|
if entityAPI.GetType(entity) ~= "character" then return end
|
||||||
|
|
||||||
|
--move the character
|
||||||
|
characterAPI.SetRoom(entity, roomOne)
|
||||||
|
characterAPI.SetOrigin(entity, Xone, Yone-16) --NOTE: the 16 pixel margin for presentation
|
||||||
|
networkAPI.PumpCharacterUpdate(entity)
|
||||||
|
|
||||||
|
--disable the other trigger
|
||||||
|
local triggerOne = triggerManagerAPI.GetTrigger(roomAPI.GetTriggerMgr(roomOne), handle)
|
||||||
|
triggerAPI.PushExclusionEntity(triggerOne, entity)
|
||||||
|
end
|
||||||
|
|
||||||
|
--create the triggers proper
|
||||||
|
doorUtility.createTrigger(handle, roomOne, Xone, Yone, scriptOne)
|
||||||
|
doorUtility.createTrigger(handle, roomTwo, Xtwo, Ytwo, scriptTwo)
|
||||||
|
end
|
||||||
|
|
||||||
|
return doorUtility
|
||||||
+91
-21
@@ -1,39 +1,109 @@
|
|||||||
local mapSystem = require "map_system"
|
local regionAPI = require("region")
|
||||||
|
|
||||||
local mapMaker = {}
|
local mapMaker = {}
|
||||||
|
|
||||||
--utility functions
|
--utility functions
|
||||||
function mapMaker.sqr(x) return x*x end
|
function mapMaker.Sqr(x) return x*x end
|
||||||
function mapMaker.dist(x, y, i, j) return math.sqrt(mapMaker.sqr(x - i) + mapMaker.sqr(y - j)) end
|
function mapMaker.Dist(x, y, i, j) return math.sqrt(mapMaker.Sqr(x - i) + mapMaker.Sqr(y - j)) end
|
||||||
|
|
||||||
--tile macros, mapped to the tilesheet "overworld.bmp"
|
--tile macros, mapped to the tilesheet "overworld.bmp"
|
||||||
mapMaker.edges = {}
|
mapMaker.blank = 0
|
||||||
mapMaker.edges.north = -16
|
|
||||||
mapMaker.edges.south = 16
|
|
||||||
mapMaker.edges.east = 1
|
|
||||||
mapMaker.edges.west = -1
|
|
||||||
|
|
||||||
mapMaker.water = 18 + 3 * 0
|
mapMaker.water = 18 + 3 * 0
|
||||||
mapMaker.sand = 18 + 3 * 1
|
mapMaker.sand = 18 + 3 * 1
|
||||||
mapMaker.plains = 18 + 3 * 2
|
mapMaker.plains = 18 + 3 * 2
|
||||||
mapMaker.grass = 18 + 3 * 3
|
mapMaker.grass = 18 + 3 * 3
|
||||||
mapMaker.dirt = 18 + 3 * 4
|
mapMaker.dirt = 18 + 3 * 4
|
||||||
|
|
||||||
--custom generation systems here
|
--"edge" macros
|
||||||
function mapMaker.debugIsland(region)
|
mapMaker.edges = {}
|
||||||
for i = 1, mapSystem.Region.GetWidth(region) do
|
mapMaker.edges.north = -16
|
||||||
for j = 1, mapSystem.Region.GetHeight(region) do
|
mapMaker.edges.south = 16
|
||||||
local dist = mapMaker.dist(0, 0, i + mapSystem.Region.GetX(region) -1, j + mapSystem.Region.GetY(region) -1)
|
mapMaker.edges.east = 1
|
||||||
if dist < 10 then
|
mapMaker.edges.west = -1
|
||||||
mapSystem.Region.SetTile(region, i, j, 1, mapMaker.plains)
|
|
||||||
elseif dist < 12 then
|
--TODO: (1) path system
|
||||||
mapSystem.Region.SetTile(region, i, j, 1, mapMaker.sand)
|
--use these macros (mapped to "overworld.bmp" for now) to smooth the region's edges
|
||||||
else
|
function mapMaker.SmoothEdgesSimple(r)
|
||||||
mapSystem.Region.SetTile(region, i, j, 1, mapMaker.water)
|
--make and pad an array to use
|
||||||
mapSystem.Region.SetSolid(region, i, j, true)
|
local shiftArray = {}
|
||||||
|
for i = 1, regionAPI.GetWidth(r) do
|
||||||
|
shiftArray[i] = {}
|
||||||
|
for j = 1, regionAPI.GetHeight(r) do
|
||||||
|
shiftArray[i][j] = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--build the array
|
||||||
|
for i = 1, regionAPI.GetWidth(r) do
|
||||||
|
for j = 1, regionAPI.GetHeight(r) do
|
||||||
|
--if (not regionAPI edge) and (west tile < this tile), etc.
|
||||||
|
if i > 1 and regionAPI.GetTile(r, i - 1, j, 1) < regionAPI.GetTile(r, i, j, 1) then
|
||||||
|
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.west
|
||||||
|
end
|
||||||
|
if j > 1 and regionAPI.GetTile(r, i, j - 1, 1) < regionAPI.GetTile(r, i, j, 1) then
|
||||||
|
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.north
|
||||||
|
end
|
||||||
|
if i < regionAPI.GetWidth(r) and regionAPI.GetTile(r, i + 1, j, 1) < regionAPI.GetTile(r, i, j, 1) then
|
||||||
|
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.east
|
||||||
|
end
|
||||||
|
if j < regionAPI.GetHeight(r) and regionAPI.GetTile(r, i, j + 1, 1) < regionAPI.GetTile(r, i, j, 1) then
|
||||||
|
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.south
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--finally apply this
|
||||||
|
for i = 1, regionAPI.GetWidth(r) do
|
||||||
|
for j = 1, regionAPI.GetHeight(r) do
|
||||||
|
if shiftArray[i][j] ~= 0 then
|
||||||
|
regionAPI.SetTile(r, i, j, 2, regionAPI.GetTile(r, i, j, 1) + shiftArray[i][j])
|
||||||
|
regionAPI.SetTile(r, i, j, 1, regionAPI.GetTile(r, i, j, 1) - 3)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--custom generation systems here
|
||||||
|
function mapMaker.DebugIsland(r)
|
||||||
|
--basic distance check for each tile, placing an island around the world origin
|
||||||
|
for i = 1, regionAPI.GetWidth(r) do
|
||||||
|
for j = 1, regionAPI.GetHeight(r) do
|
||||||
|
local dist = mapMaker.Dist(0, 0, i + regionAPI.GetX(r) -1, j + regionAPI.GetY(r) -1)
|
||||||
|
if dist < 10 then
|
||||||
|
regionAPI.SetTile(r, i, j, 1, mapMaker.plains)
|
||||||
|
elseif dist < 12 then
|
||||||
|
regionAPI.SetTile(r, i, j, 1, mapMaker.sand)
|
||||||
|
else
|
||||||
|
regionAPI.SetTile(r, i, j, 1, mapMaker.water)
|
||||||
|
regionAPI.SetSolid(r, i, j, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--examples of the smoothing function NOT working correctly
|
||||||
|
--[[
|
||||||
|
for j = 1, regionAPI.GetHeight(r) do
|
||||||
|
regionAPI.SetTile(r, 3, j, 1, mapMaker.dirt)
|
||||||
|
regionAPI.SetTile(r, 4, j, 1, mapMaker.dirt)
|
||||||
|
|
||||||
|
regionAPI.SetTile(r, 10, j, 1, mapMaker.dirt)
|
||||||
|
end
|
||||||
|
--]]
|
||||||
|
|
||||||
|
--A generic edge system
|
||||||
|
mapMaker.SmoothEdgesSimple(r)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mapMaker.DebugGrassland(r)
|
||||||
|
--all dirt
|
||||||
|
for i = 1, regionAPI.GetWidth(r) do
|
||||||
|
for j = 1, regionAPI.GetHeight(r) do
|
||||||
|
regionAPI.SetTile(r, i, j, 1, mapMaker.grass)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--A generic edge system
|
||||||
|
-- mapMaker.SmoothEdgesSimple(r)
|
||||||
|
end
|
||||||
|
|
||||||
return mapMaker
|
return mapMaker
|
||||||
@@ -1,9 +1,15 @@
|
|||||||
|
local region = require("region")
|
||||||
|
|
||||||
local mapSaver = {}
|
local mapSaver = {}
|
||||||
function mapSaver.Load(region)
|
|
||||||
|
function mapSaver.Load(r)
|
||||||
--empty
|
--empty
|
||||||
|
io.write("map_saver:Load(", region.GetX(r), ", ", region.GetY(r), ")\n")
|
||||||
end
|
end
|
||||||
function mapSaver.Save(region)
|
function mapSaver.Save(r)
|
||||||
--empty
|
--empty
|
||||||
|
io.write("map_saver:Save(", region.GetX(r), ", ", region.GetY(r), ")\n")
|
||||||
end
|
end
|
||||||
--TODO: create a flexible saving & loading system
|
|
||||||
|
--TODO: (3) create a flexible saving & loading system
|
||||||
return mapSaver
|
return mapSaver
|
||||||
@@ -1,32 +1,36 @@
|
|||||||
print("Lua script check")
|
print("Lua script check")
|
||||||
|
|
||||||
mapMaker = require "map_maker"
|
--requirements
|
||||||
mapSaver = require "map_saver"
|
roomManagerAPI = require("room_manager")
|
||||||
roomSystem = require "room_system"
|
roomAPI = require("room")
|
||||||
|
|
||||||
local function dumpTable(t)
|
mapMaker = require("map_maker")
|
||||||
print(t)
|
mapSaver = require("map_saver")
|
||||||
for k, v in pairs(t) do
|
|
||||||
print("",k, v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--create the overworld, set it's generator, loader & saver
|
doorUtility = require("door_utility")
|
||||||
--[[
|
|
||||||
local t = {
|
|
||||||
"overworld.bmp", --tileset name
|
|
||||||
mapSaver.load, --load function
|
|
||||||
mapSaver.save, --save function
|
|
||||||
mapMaker.debugIsland, --create function
|
|
||||||
mapSaver.save --unload function
|
|
||||||
}]]
|
|
||||||
|
|
||||||
dumpTable(roomSystem)
|
--test the room hooks
|
||||||
dumpTable(roomSystem.RoomManager)
|
roomManagerAPI.SetOnCreate(function(room, index)
|
||||||
dumpTable(roomSystem.Room)
|
print("", "Creating room: ", roomAPI.GetName(room), index)
|
||||||
|
|
||||||
|
roomAPI.SetOnTick(room, function(room)
|
||||||
|
roomAPI.ForEachCharacter(room, function(character)
|
||||||
|
--
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
roomManagerAPI.SetOnUnload(function(room, index)
|
||||||
|
print("", "Unloading room: ", roomAPI.GetName(room), index)
|
||||||
|
end)
|
||||||
|
|
||||||
--NOTE: room 0 is the first that the client asks for, therefore it must exist
|
--NOTE: room 0 is the first that the client asks for, therefore it must exist
|
||||||
local overworld, uid = roomSystem.RoomManager.CreateRoom("overworld")
|
local overworld, uidOne = roomManagerAPI.CreateRoom("overworld", "overworld.bmp")
|
||||||
roomSystem.Room.Initialize(overworld, "overworld.bmp", mapSaver.Load, mapSaver.Save, mapMaker.debugIsland, mapSaver.Save)
|
roomAPI.Initialize(overworld, mapSaver.Load, mapSaver.Save, mapMaker.DebugIsland, mapSaver.Save)
|
||||||
|
local underworld, uidTwo = roomManagerAPI.CreateRoom("underworld", "overworld.bmp")
|
||||||
|
roomAPI.Initialize(underworld, mapSaver.Load, mapSaver.Save, mapMaker.DebugGrassland, mapSaver.Save)
|
||||||
|
|
||||||
|
--call the monstrosity
|
||||||
|
doorUtility.createDoorPair("pair 1", overworld, 0, -64, underworld, 0, 0)
|
||||||
|
|
||||||
print("Finished the lua script")
|
print("Finished the lua script")
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
--TODO: An archive table of all dead characters
|
--TODO: (3) An archive table of all dead characters
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS Accounts (
|
CREATE TABLE IF NOT EXISTS Accounts (
|
||||||
uid INTEGER PRIMARY KEY AUTOINCREMENT,
|
uid INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
username varchar(100) UNIQUE,
|
username varchar(100) UNIQUE, --TODO: (3) Swap username for email address
|
||||||
|
|
||||||
--TODO: server-client security
|
--server-client security
|
||||||
-- passhash varchar(100),
|
-- passhash varchar(100),
|
||||||
-- passsalt varchar(100),
|
-- passsalt varchar(100),
|
||||||
|
|
||||||
@@ -24,10 +24,14 @@ CREATE TABLE IF NOT EXISTS Characters (
|
|||||||
avatar varchar(100),
|
avatar varchar(100),
|
||||||
birth timestamp NOT NULL DEFAULT (datetime()),
|
birth timestamp NOT NULL DEFAULT (datetime()),
|
||||||
|
|
||||||
--position in the world
|
--physically exists in the world
|
||||||
roomIndex INTEGER DEFAULT 0,
|
roomIndex INTEGER DEFAULT 0,
|
||||||
originX INTEGER DEFAULT 0,
|
originX INTEGER DEFAULT 0,
|
||||||
originY INTEGER DEFAULT 0,
|
originY INTEGER DEFAULT 0,
|
||||||
|
boundsX INTEGER DEFAULT 0,
|
||||||
|
boundsY INTEGER DEFAULT 0,
|
||||||
|
boundsW INTEGER DEFAULT 0,
|
||||||
|
boundsH INTEGER DEFAULT 0,
|
||||||
|
|
||||||
--statistics
|
--statistics
|
||||||
baseStats INTEGER REFERENCES StatisticSets(uid),
|
baseStats INTEGER REFERENCES StatisticSets(uid),
|
||||||
@@ -101,5 +105,5 @@ CREATE TABLE IF NOT EXISTS WornEquipment (
|
|||||||
--unique information
|
--unique information
|
||||||
durability INTEGER DEFAULT 0,
|
durability INTEGER DEFAULT 0,
|
||||||
stats INTEGER REFERENCES StatisticSets(uid)
|
stats INTEGER REFERENCES StatisticSets(uid)
|
||||||
--TODO: attached script?
|
--attached script?
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ private:
|
|||||||
|
|
||||||
int clientIndex;
|
int clientIndex;
|
||||||
std::string username;
|
std::string username;
|
||||||
//TODO: password
|
//password/auth token
|
||||||
|
|
||||||
//bit fields?
|
//bit fields?
|
||||||
bool blackListed = false;
|
bool blackListed = false;
|
||||||
|
|||||||
@@ -28,15 +28,31 @@
|
|||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
static const char* CREATE_USER_ACCOUNT = "INSERT INTO Accounts (username) VALUES (?);";
|
static const char* CREATE_USER_ACCOUNT = "INSERT INTO Accounts (username) VALUES (?);";
|
||||||
static const char* LOAD_USER_ACCOUNT = "SELECT * FROM Accounts WHERE username = ?;";
|
|
||||||
static const char* SAVE_USER_ACCOUNT = "UPDATE OR FAIL Accounts SET blacklisted = ?2, whitelisted = ?3, mod = ?4, admin = ?5 WHERE uid = ?1;";
|
static const char* LOAD_USER_ACCOUNT = "SELECT "
|
||||||
|
"uid, "
|
||||||
|
"blacklisted, "
|
||||||
|
"whitelisted, "
|
||||||
|
"mod, "
|
||||||
|
"admin "
|
||||||
|
" FROM Accounts WHERE username = ?;";
|
||||||
|
|
||||||
|
static const char* SAVE_USER_ACCOUNT = "UPDATE OR FAIL Accounts SET "
|
||||||
|
"blacklisted = ?2, "
|
||||||
|
"whitelisted = ?3, "
|
||||||
|
"mod = ?4, "
|
||||||
|
"admin = ?5 "
|
||||||
|
"WHERE uid = ?1;";
|
||||||
|
|
||||||
static const char* DELETE_USER_ACCOUNT = "DELETE FROM Accounts WHERE uid = ?;";
|
static const char* DELETE_USER_ACCOUNT = "DELETE FROM Accounts WHERE uid = ?;";
|
||||||
|
|
||||||
static const char* COUNT_USER_ACCOUNT_RECORDS = "SELECT COUNT(*) FROM Accounts;";
|
static const char* COUNT_USER_ACCOUNT_RECORDS = "SELECT COUNT(*) FROM Accounts;";
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//Define the public methods
|
//Define the public methods
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
|
//TODO: (1) block blacklisted accounts
|
||||||
int AccountManager::Create(std::string username, int clientIndex) {
|
int AccountManager::Create(std::string username, int clientIndex) {
|
||||||
//create this user account, failing if it exists, leave this account in memory
|
//create this user account, failing if it exists, leave this account in memory
|
||||||
sqlite3_stmt* statement = nullptr;
|
sqlite3_stmt* statement = nullptr;
|
||||||
@@ -94,11 +110,11 @@ int AccountManager::Load(std::string username, int clientIndex) {
|
|||||||
|
|
||||||
//extract the data into memory
|
//extract the data into memory
|
||||||
AccountData& newAccount = elementMap[uid];
|
AccountData& newAccount = elementMap[uid];
|
||||||
newAccount.username = reinterpret_cast<const char*>(sqlite3_column_text(statement, 1));
|
newAccount.username = username;
|
||||||
newAccount.blackListed = sqlite3_column_int(statement, 2);
|
newAccount.blackListed = sqlite3_column_int(statement, 1);
|
||||||
newAccount.whiteListed = sqlite3_column_int(statement, 3);
|
newAccount.whiteListed = sqlite3_column_int(statement, 2);
|
||||||
newAccount.mod = sqlite3_column_int(statement, 4);
|
newAccount.mod = sqlite3_column_int(statement, 3);
|
||||||
newAccount.admin = sqlite3_column_int(statement, 5);
|
newAccount.admin = sqlite3_column_int(statement, 4);
|
||||||
newAccount.clientIndex = clientIndex;
|
newAccount.clientIndex = clientIndex;
|
||||||
|
|
||||||
//finish the routine
|
//finish the routine
|
||||||
@@ -200,7 +216,7 @@ void AccountManager::UnloadAll() {
|
|||||||
elementMap.clear();
|
elementMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountManager::UnloadIf(std::function<bool(std::pair<const int, AccountData>)> fn) {
|
void AccountManager::UnloadIf(std::function<bool(std::pair<const int, AccountData const&>)> fn) {
|
||||||
//replicate std::remove_if, using custom code
|
//replicate std::remove_if, using custom code
|
||||||
std::map<int, AccountData>::iterator it = elementMap.begin();
|
std::map<int, AccountData>::iterator it = elementMap.begin();
|
||||||
while (it != elementMap.end()) {
|
while (it != elementMap.end()) {
|
||||||
@@ -219,7 +235,6 @@ void AccountManager::UnloadIf(std::function<bool(std::pair<const int, AccountDat
|
|||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
AccountData* AccountManager::Get(int uid) {
|
AccountData* AccountManager::Get(int uid) {
|
||||||
//TODO: could this load an account first?
|
|
||||||
std::map<int, AccountData>::iterator it = elementMap.find(uid);
|
std::map<int, AccountData>::iterator it = elementMap.find(uid);
|
||||||
|
|
||||||
if (it == elementMap.end()) {
|
if (it == elementMap.end()) {
|
||||||
|
|||||||
@@ -24,37 +24,29 @@
|
|||||||
|
|
||||||
#include "account_data.hpp"
|
#include "account_data.hpp"
|
||||||
#include "singleton.hpp"
|
#include "singleton.hpp"
|
||||||
#include "manager_interface.hpp"
|
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#include "sqlite3.h"
|
||||||
#include "sqlite3/sqlite3.h"
|
|
||||||
#else
|
|
||||||
#include "sqlite3.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
class AccountManager:
|
class AccountManager: public Singleton<AccountManager> {
|
||||||
public Singleton<AccountManager>,
|
|
||||||
public ManagerInterface<AccountData, std::string, int>
|
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
//common public methods
|
//common public methods
|
||||||
int Create(std::string username, int clientIndex) override;
|
int Create(std::string username, int clientIndex);
|
||||||
int Load(std::string username, int clientIndex) override;
|
int Load(std::string username, int clientIndex);
|
||||||
int Save(int uid) override;
|
int Save(int uid);
|
||||||
void Unload(int uid) override;
|
void Unload(int uid);
|
||||||
void Delete(int uid) override;
|
void Delete(int uid);
|
||||||
|
|
||||||
void UnloadAll() override;
|
void UnloadAll();
|
||||||
void UnloadIf(std::function<bool(std::pair<const int, AccountData>)> fn) override;
|
void UnloadIf(std::function<bool(std::pair<const int, AccountData const&>)> fn);
|
||||||
|
|
||||||
//accessors and mutators
|
//accessors and mutators
|
||||||
AccountData* Get(int uid) override;
|
AccountData* Get(int uid);
|
||||||
int GetLoadedCount() override;
|
int GetLoadedCount();
|
||||||
int GetTotalCount() override;
|
int GetTotalCount();
|
||||||
std::map<int, AccountData>* GetContainer() override;
|
std::map<int, AccountData>* GetContainer();
|
||||||
|
|
||||||
sqlite3* SetDatabase(sqlite3* db);
|
sqlite3* SetDatabase(sqlite3* db);
|
||||||
sqlite3* GetDatabase();
|
sqlite3* GetDatabase();
|
||||||
@@ -65,6 +57,8 @@ private:
|
|||||||
AccountManager() = default;
|
AccountManager() = default;
|
||||||
~AccountManager() = default;
|
~AccountManager() = default;
|
||||||
|
|
||||||
|
//members
|
||||||
|
std::map<int, AccountData> elementMap;
|
||||||
sqlite3* database = nullptr;
|
sqlite3* database = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "character_api.hpp"
|
||||||
|
|
||||||
|
#include "character_data.hpp"
|
||||||
|
#include "character_manager.hpp"
|
||||||
|
#include "entity_api.hpp"
|
||||||
|
#include "room_manager.hpp"
|
||||||
|
#include "server_utilities.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
static int setRoom(lua_State* L) {
|
||||||
|
//reverse engineer the character index
|
||||||
|
int characterIndex = -1;
|
||||||
|
CharacterData* character = static_cast<CharacterData*>(lua_touserdata(L, 1));
|
||||||
|
CharacterManager& characterMgr = CharacterManager::GetSingleton();
|
||||||
|
|
||||||
|
for (auto& it : *characterMgr.GetContainer()) {
|
||||||
|
if (character == &it.second) {
|
||||||
|
characterIndex = it.first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//error checking
|
||||||
|
if (characterIndex == -1) {
|
||||||
|
throw(std::runtime_error("Lua Error: Failed to find character index by reference"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the room index, depending on the parameter type
|
||||||
|
int roomIndex = -1;
|
||||||
|
RoomManager& roomMgr = RoomManager::GetSingleton();
|
||||||
|
switch(lua_type(L, 2)) {
|
||||||
|
case LUA_TNUMBER:
|
||||||
|
roomIndex = lua_tointeger(L, 2);
|
||||||
|
break;
|
||||||
|
case LUA_TLIGHTUSERDATA:
|
||||||
|
//reverse engineer the room index
|
||||||
|
for (auto& it : *roomMgr.GetContainer()) {
|
||||||
|
if (lua_touserdata(L, 2) == &it.second) {
|
||||||
|
roomIndex = it.first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//error checking
|
||||||
|
if (roomIndex == -1) {
|
||||||
|
throw(std::runtime_error("Lua Error: Failed to find room index by reference"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//send the delete & create messages
|
||||||
|
pumpAndChangeRooms(character, roomIndex, characterIndex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getOwner(lua_State* L) {
|
||||||
|
CharacterData* character = static_cast<CharacterData*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushinteger(L, character->GetOwner());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getHandle(lua_State* L) {
|
||||||
|
CharacterData* character = static_cast<CharacterData*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushstring(L, character->GetHandle().c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getAvatar(lua_State* L) {
|
||||||
|
CharacterData* character = static_cast<CharacterData*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushstring(L, character->GetAvatar().c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const luaL_Reg characterLib[] = {
|
||||||
|
{"SetRoom", setRoom},
|
||||||
|
// {"GetOwner", getOwner}, //unusable without account API
|
||||||
|
{"GetHandle", getHandle},
|
||||||
|
{"GetAvatar", getAvatar},
|
||||||
|
{nullptr, nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
|
LUAMOD_API int openCharacterAPI(lua_State* L) {
|
||||||
|
//get the parent table
|
||||||
|
luaL_requiref(L, TORTUGA_ENTITY_API, openEntityAPI, false);
|
||||||
|
|
||||||
|
//the local table
|
||||||
|
luaL_newlib(L, characterLib);
|
||||||
|
|
||||||
|
//merge the local table into the parent table
|
||||||
|
lua_pushnil(L); //first key
|
||||||
|
while(lua_next(L, -2)) {
|
||||||
|
//copy the key-value pair
|
||||||
|
lua_pushvalue(L, -2);
|
||||||
|
lua_pushvalue(L, -2);
|
||||||
|
|
||||||
|
//push the copy to the parent table
|
||||||
|
lua_settable(L, -6);
|
||||||
|
|
||||||
|
//pop the original value before continuing
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove the local table, leaving the expanded parent table
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -19,16 +19,12 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef MAPSYSTEMAPI_HPP_
|
#ifndef CHARACTERAPI_HPP_
|
||||||
#define MAPSYSTEMAPI_APP_
|
#define CHARACTERAPI_HPP_
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#include "lua.hpp"
|
||||||
#include "lua/lua.hpp"
|
|
||||||
#else
|
|
||||||
#include "lua.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TORTUGA_MAP_SYSTEM_API "map_system"
|
#define TORTUGA_CHARACTER_API "character"
|
||||||
LUAMOD_API int openMapSystemAPI(lua_State* L);
|
LUAMOD_API int openCharacterAPI(lua_State* L);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -21,6 +21,10 @@
|
|||||||
*/
|
*/
|
||||||
#include "character_data.hpp"
|
#include "character_data.hpp"
|
||||||
|
|
||||||
|
CharacterData::CharacterData(): Entity("character") {
|
||||||
|
//EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
int CharacterData::GetOwner() {
|
int CharacterData::GetOwner() {
|
||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,12 +32,9 @@
|
|||||||
|
|
||||||
class CharacterData: public Entity {
|
class CharacterData: public Entity {
|
||||||
public:
|
public:
|
||||||
CharacterData() = default;
|
CharacterData();
|
||||||
~CharacterData() = default;
|
~CharacterData() = default;
|
||||||
|
|
||||||
//accessors and mutators
|
|
||||||
//...
|
|
||||||
|
|
||||||
//database stuff
|
//database stuff
|
||||||
int GetOwner();
|
int GetOwner();
|
||||||
std::string GetHandle();
|
std::string GetHandle();
|
||||||
@@ -46,7 +43,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class CharacterManager;
|
friend class CharacterManager;
|
||||||
|
|
||||||
int owner;
|
int owner = -1;
|
||||||
std::string handle;
|
std::string handle;
|
||||||
std::string avatar;
|
std::string avatar;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,11 +21,9 @@
|
|||||||
*/
|
*/
|
||||||
#include "character_manager.hpp"
|
#include "character_manager.hpp"
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#include "sqlite3.h"
|
||||||
#include "sqlite3/sqlite3.h"
|
|
||||||
#else
|
#include "character_defines.hpp"
|
||||||
#include "sqlite3.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -34,10 +32,45 @@
|
|||||||
//Define the queries
|
//Define the queries
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
static const char* CREATE_CHARACTER = "INSERT INTO Characters (owner, handle, avatar) VALUES (?, ?, ?);";
|
//NOTE: Programmer set variables are NOT zero-indexed
|
||||||
static const char* LOAD_CHARACTER = "SELECT * FROM Characters WHERE handle = ?;";
|
//NOTE: SQLite3 returned variables (i.e. loading) ARE zero-indexed
|
||||||
static const char* SAVE_CHARACTER = "UPDATE OR FAIL Characters SET roomIndex = ?2, originX = ?3, originY = ?4 WHERE uid = ?1;";
|
|
||||||
|
static const char* CREATE_CHARACTER = "INSERT INTO Characters ("
|
||||||
|
"owner, "
|
||||||
|
"handle, "
|
||||||
|
"avatar, "
|
||||||
|
"boundsX, "
|
||||||
|
"boundsY, "
|
||||||
|
"boundsW, "
|
||||||
|
"boundsH"
|
||||||
|
") VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7);";
|
||||||
|
|
||||||
|
static const char* LOAD_CHARACTER = "SELECT "
|
||||||
|
"uid, "
|
||||||
|
"owner, "
|
||||||
|
"handle, "
|
||||||
|
"avatar, "
|
||||||
|
"roomIndex, "
|
||||||
|
"originX, "
|
||||||
|
"originY, "
|
||||||
|
"boundsX, "
|
||||||
|
"boundsY, "
|
||||||
|
"boundsW, "
|
||||||
|
"boundsH "
|
||||||
|
"FROM Characters WHERE handle = ?;";
|
||||||
|
|
||||||
|
static const char* SAVE_CHARACTER = "UPDATE OR FAIL Characters SET "
|
||||||
|
"roomIndex = ?2, "
|
||||||
|
"originX = ?3, "
|
||||||
|
"originY = ?4, "
|
||||||
|
"boundsX = ?5, "
|
||||||
|
"boundsY = ?6, "
|
||||||
|
"boundsW = ?7, "
|
||||||
|
"boundsH = ?8 "
|
||||||
|
"WHERE uid = ?1;";
|
||||||
|
|
||||||
static const char* DELETE_CHARACTER = "DELETE FROM Characters WHERE uid = ?;";
|
static const char* DELETE_CHARACTER = "DELETE FROM Characters WHERE uid = ?;";
|
||||||
|
|
||||||
static const char* COUNT_CHARACTER_RECORDS = "SELECT COUNT(*) FROM Characters;";
|
static const char* COUNT_CHARACTER_RECORDS = "SELECT COUNT(*) FROM Characters;";
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
@@ -59,6 +92,10 @@ int CharacterManager::Create(int owner, std::string handle, std::string avatar)
|
|||||||
ret |= sqlite3_bind_int(statement, 1, owner);
|
ret |= sqlite3_bind_int(statement, 1, owner);
|
||||||
ret |= sqlite3_bind_text(statement, 2, handle.c_str(), handle.size() + 1, SQLITE_STATIC);
|
ret |= sqlite3_bind_text(statement, 2, handle.c_str(), handle.size() + 1, SQLITE_STATIC);
|
||||||
ret |= sqlite3_bind_text(statement, 3, avatar.c_str(), avatar.size() + 1, SQLITE_STATIC);
|
ret |= sqlite3_bind_text(statement, 3, avatar.c_str(), avatar.size() + 1, SQLITE_STATIC);
|
||||||
|
ret |= sqlite3_bind_int(statement, 4, CHARACTER_BOUNDS_X);
|
||||||
|
ret |= sqlite3_bind_int(statement, 5, CHARACTER_BOUNDS_Y);
|
||||||
|
ret |= sqlite3_bind_int(statement, 6, CHARACTER_BOUNDS_WIDTH);
|
||||||
|
ret |= sqlite3_bind_int(statement, 7, CHARACTER_BOUNDS_HEIGHT);
|
||||||
|
|
||||||
//check for binding errors
|
//check for binding errors
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -125,9 +162,14 @@ int CharacterManager::Load(int owner, std::string handle, std::string avatar) {
|
|||||||
//Don't cache the birth
|
//Don't cache the birth
|
||||||
|
|
||||||
//world origin
|
//world origin
|
||||||
newChar.roomIndex = sqlite3_column_int(statement, 5);
|
newChar.roomIndex = sqlite3_column_int(statement, 4);
|
||||||
newChar.origin.x = (double)sqlite3_column_int(statement, 6);
|
newChar.origin.x = (double)sqlite3_column_int(statement, 5);
|
||||||
newChar.origin.y = (double)sqlite3_column_int(statement, 7);
|
newChar.origin.y = (double)sqlite3_column_int(statement, 6);
|
||||||
|
//bounds
|
||||||
|
newChar.bounds.x = (int)sqlite3_column_int(statement, 7);
|
||||||
|
newChar.bounds.y = (int)sqlite3_column_int(statement, 8);
|
||||||
|
newChar.bounds.w = (int)sqlite3_column_int(statement, 9);
|
||||||
|
newChar.bounds.h = (int)sqlite3_column_int(statement, 10);
|
||||||
|
|
||||||
//gameplay components: equipment, items, buffs, debuffs...
|
//gameplay components: equipment, items, buffs, debuffs...
|
||||||
|
|
||||||
@@ -169,6 +211,10 @@ int CharacterManager::Save(int uid) {
|
|||||||
ret |= sqlite3_bind_int(statement, 2, character.roomIndex) != SQLITE_OK;
|
ret |= sqlite3_bind_int(statement, 2, character.roomIndex) != SQLITE_OK;
|
||||||
ret |= sqlite3_bind_int(statement, 3, (int)character.origin.x) != SQLITE_OK;
|
ret |= sqlite3_bind_int(statement, 3, (int)character.origin.x) != SQLITE_OK;
|
||||||
ret |= sqlite3_bind_int(statement, 4, (int)character.origin.y) != SQLITE_OK;
|
ret |= sqlite3_bind_int(statement, 4, (int)character.origin.y) != SQLITE_OK;
|
||||||
|
ret |= sqlite3_bind_int(statement, 5, character.bounds.x) != SQLITE_OK;
|
||||||
|
ret |= sqlite3_bind_int(statement, 6, character.bounds.y) != SQLITE_OK;
|
||||||
|
ret |= sqlite3_bind_int(statement, 7, character.bounds.w) != SQLITE_OK;
|
||||||
|
ret |= sqlite3_bind_int(statement, 8, character.bounds.h) != SQLITE_OK;
|
||||||
|
|
||||||
//gameplay components: equipment, items, buffs, debuffs...
|
//gameplay components: equipment, items, buffs, debuffs...
|
||||||
|
|
||||||
@@ -197,6 +243,7 @@ void CharacterManager::Unload(int uid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CharacterManager::Delete(int uid) {
|
void CharacterManager::Delete(int uid) {
|
||||||
|
//TODO: when deleting a character, move it to an archive table
|
||||||
//delete this character from the database, then remove it from memory
|
//delete this character from the database, then remove it from memory
|
||||||
sqlite3_stmt* statement = nullptr;
|
sqlite3_stmt* statement = nullptr;
|
||||||
|
|
||||||
@@ -229,7 +276,7 @@ void CharacterManager::UnloadAll() {
|
|||||||
elementMap.clear();
|
elementMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterManager::UnloadIf(std::function<bool(std::pair<const int, CharacterData>)> fn) {
|
void CharacterManager::UnloadIf(std::function<bool(std::pair<const int, CharacterData const&>)> fn) {
|
||||||
std::map<int, CharacterData>::iterator it = elementMap.begin();
|
std::map<int, CharacterData>::iterator it = elementMap.begin();
|
||||||
while (it != elementMap.end()) {
|
while (it != elementMap.end()) {
|
||||||
if (fn(*it)) {
|
if (fn(*it)) {
|
||||||
@@ -256,6 +303,15 @@ CharacterData* CharacterManager::Get(int uid) {
|
|||||||
return &it->second;
|
return &it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CharacterData* CharacterManager::Get(std::string handle) {
|
||||||
|
for (std::map<int, CharacterData>::iterator it = elementMap.begin(); it != elementMap.end(); ++it) {
|
||||||
|
if (it->second.GetHandle() == handle) {
|
||||||
|
return &it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
int CharacterManager::GetLoadedCount() {
|
int CharacterManager::GetLoadedCount() {
|
||||||
return elementMap.size();
|
return elementMap.size();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,47 +24,46 @@
|
|||||||
|
|
||||||
#include "character_data.hpp"
|
#include "character_data.hpp"
|
||||||
#include "singleton.hpp"
|
#include "singleton.hpp"
|
||||||
#include "manager_interface.hpp"
|
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#include "sqlite3.h"
|
||||||
#include "sqlite3/sqlite3.h"
|
|
||||||
#else
|
|
||||||
#include "sqlite3.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
class CharacterManager:
|
class CharacterManager: public Singleton<CharacterManager> {
|
||||||
public Singleton<CharacterManager>,
|
|
||||||
public ManagerInterface<CharacterData, int, std::string, std::string>
|
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
//common public methods
|
//common public methods
|
||||||
int Create(int owner, std::string handle, std::string avatar) override;
|
int Create(int owner, std::string handle, std::string avatar);
|
||||||
int Load(int owner, std::string handle, std::string avatar) override;
|
int Load(int owner, std::string handle, std::string avatar);
|
||||||
int Save(int uid) override;
|
int Save(int uid);
|
||||||
void Unload(int uid) override;
|
void Unload(int uid);
|
||||||
void Delete(int uid) override;
|
void Delete(int uid);
|
||||||
|
|
||||||
void UnloadAll() override;
|
void UnloadAll();
|
||||||
void UnloadIf(std::function<bool(std::pair<const int, CharacterData>)> fn) override;
|
void UnloadIf(std::function<bool(std::pair<const int, CharacterData const&>)> fn);
|
||||||
|
|
||||||
//accessors and mutators
|
//accessors and mutators
|
||||||
CharacterData* Get(int uid) override;
|
CharacterData* Get(int uid);
|
||||||
int GetLoadedCount() override;
|
CharacterData* Get(std::string handle);
|
||||||
int GetTotalCount() override;
|
int GetLoadedCount();
|
||||||
std::map<int, CharacterData>* GetContainer() override;
|
int GetTotalCount();
|
||||||
|
std::map<int, CharacterData>* GetContainer();
|
||||||
|
|
||||||
|
//API interface
|
||||||
sqlite3* SetDatabase(sqlite3* db);
|
sqlite3* SetDatabase(sqlite3* db);
|
||||||
sqlite3* GetDatabase();
|
sqlite3* GetDatabase();
|
||||||
|
|
||||||
|
//hooks
|
||||||
|
//TODO: character hooks
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend Singleton<CharacterManager>;
|
friend Singleton<CharacterManager>;
|
||||||
|
|
||||||
CharacterManager() = default;
|
CharacterManager() = default;
|
||||||
~CharacterManager() = default;
|
~CharacterManager() = default;
|
||||||
|
|
||||||
|
//members
|
||||||
|
std::map<int, CharacterData> elementMap;
|
||||||
sqlite3* database = nullptr;
|
sqlite3* database = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "character_manager_api.hpp"
|
||||||
|
|
||||||
|
#include "character_manager.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
//TODO: (1) character hooks?
|
||||||
|
|
||||||
|
static int setOnCreate(lua_State* L) {
|
||||||
|
//TODO: (9) setOnCreate()
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setOnLoad(lua_State* L) {
|
||||||
|
//TODO: (9) setOnLoad()
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setOnSave(lua_State* L) {
|
||||||
|
//TODO: (9) setOnSave()
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setOnUnload(lua_State* L) {
|
||||||
|
//TODO: (9) setOnUnload()
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setOnDelete(lua_State* L) {
|
||||||
|
//TODO: (9) setOnDelete()
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getCharacter(lua_State* L) {
|
||||||
|
//integer vs name
|
||||||
|
CharacterManager& characterMgr = CharacterManager::GetSingleton();
|
||||||
|
CharacterData* characterData = nullptr;
|
||||||
|
|
||||||
|
switch(lua_type(L, 1)) {
|
||||||
|
case LUA_TNUMBER:
|
||||||
|
characterData = characterMgr.Get(lua_tointeger(L, 1));
|
||||||
|
break;
|
||||||
|
case LUA_TSTRING:
|
||||||
|
//access characters via their handles
|
||||||
|
characterData = characterMgr.Get(lua_tostring(L, 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (characterData) {
|
||||||
|
lua_pushlightuserdata(L, static_cast<void*>(characterData));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushnil(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getLoadedCount(lua_State* L) {
|
||||||
|
CharacterManager& characterMgr = CharacterManager::GetSingleton();
|
||||||
|
lua_pushinteger(L, characterMgr.GetLoadedCount());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int forEach(lua_State* L) {
|
||||||
|
CharacterManager& characterMgr = CharacterManager::GetSingleton();
|
||||||
|
//pass each character to the given function
|
||||||
|
for (auto& it : *characterMgr.GetContainer()) {
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_pushlightuserdata(L, static_cast<void*>(&it.second));
|
||||||
|
//call each iteration, throwing an exception if something happened
|
||||||
|
if (lua_pcall(L, 1, 0, 0) != LUA_OK) {
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "Lua error: ";
|
||||||
|
os << lua_tostring(L, -1);
|
||||||
|
throw(std::runtime_error(os.str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const luaL_Reg characterManagerLib[] = {
|
||||||
|
// {"SetOnCreate", setOnCreate},
|
||||||
|
// {"SetOnLoad", setOnLoad},
|
||||||
|
// {"SetOnSave", setOnSave},
|
||||||
|
// {"SetOnUnload", setOnUnload},
|
||||||
|
// {"SetOnDelete", setOnDelete},
|
||||||
|
{"GetCharacter", getCharacter},
|
||||||
|
{"GetLoadedCount", getLoadedCount},
|
||||||
|
{"ForEach", forEach},
|
||||||
|
{nullptr, nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
|
LUAMOD_API int openCharacterManagerAPI(lua_State* L) {
|
||||||
|
luaL_newlib(L, characterManagerLib);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -19,16 +19,12 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef ROOMSYSTEMAPI_HPP_
|
#ifndef CHARACTERMANAGERAPI_HPP_
|
||||||
#define ROOMSYSTEMAPI_HPP_
|
#define CHARACTERMANAGERAPI_HPP_
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#include "lua.hpp"
|
||||||
#include "lua/lua.hpp"
|
|
||||||
#else
|
|
||||||
#include "lua.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TORTUGA_ROOM_SYSTEM_API "room_system"
|
#define TORTUGA_CHARACTER_MANAGER_API "character_manager"
|
||||||
LUAMOD_API int openRoomSystemAPI(lua_State* L);
|
LUAMOD_API int openCharacterManagerAPI(lua_State* L);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#config
|
#config
|
||||||
INCLUDES+=. ../entities ../server_utilities ../../common/gameplay ../../common/utilities
|
INCLUDES+=. ../entities ../monsters ../rooms ../server_utilities ../triggers ../../common/gameplay ../../common/map ../../common/network ../../common/network/packet_types ../../common/utilities
|
||||||
LIBS+=
|
LIBS+=
|
||||||
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,15 @@
|
|||||||
*/
|
*/
|
||||||
#include "client_manager.hpp"
|
#include "client_manager.hpp"
|
||||||
|
|
||||||
|
#include "ip_operators.hpp"
|
||||||
#include "udp_network_utility.hpp"
|
#include "udp_network_utility.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
int ClientManager::CheckConnections() {
|
std::list<int> ClientManager::CheckConnections() {
|
||||||
|
//list of clients to disconnect
|
||||||
|
std::list<int> returnList;
|
||||||
|
|
||||||
for (auto& it : elementMap) {
|
for (auto& it : elementMap) {
|
||||||
//3 seconds between beats
|
//3 seconds between beats
|
||||||
if (ClientData::Clock::now() - it.second.GetLastBeat() > std::chrono::seconds(3)) {
|
if (ClientData::Clock::now() - it.second.GetLastBeat() > std::chrono::seconds(3)) {
|
||||||
@@ -38,21 +42,17 @@ int ClientManager::CheckConnections() {
|
|||||||
|
|
||||||
for (auto& it : elementMap) {
|
for (auto& it : elementMap) {
|
||||||
if (it.second.GetAttempts() > 2) {
|
if (it.second.GetAttempts() > 2) {
|
||||||
int ret = it.first;
|
returnList.push_back(it.first);
|
||||||
// elementMap.erase(it.first);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return returnList;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientManager::HandlePong(ServerPacket* const argPacket) {
|
void ClientManager::HandlePong(ServerPacket* const argPacket) {
|
||||||
//find and update the specified client
|
//find and update the specified client
|
||||||
for (auto& it : elementMap) {
|
for (auto& it : elementMap) {
|
||||||
if (it.second.GetAddress().host == argPacket->srcAddress.host &&
|
if (it.second.GetAddress() == argPacket->srcAddress) {
|
||||||
it.second.GetAddress().port == argPacket->srcAddress.port
|
|
||||||
) {
|
|
||||||
it.second.ResetAttempts();
|
it.second.ResetAttempts();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -73,12 +73,11 @@ void ClientManager::UnloadAll() {
|
|||||||
elementMap.clear();
|
elementMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientManager::UnloadIf(std::function<bool(std::pair<const int, ClientData>)> fn) {
|
void ClientManager::UnloadIf(std::function<bool(std::pair<const int, ClientData const&>)> fn) {
|
||||||
std::map<int, ClientData>::iterator it = elementMap.begin();
|
std::map<int, ClientData>::iterator it = elementMap.begin();
|
||||||
while (it != elementMap.end()) {
|
while (it != elementMap.end()) {
|
||||||
if (fn(*it)) {
|
if (fn(*it)) {
|
||||||
it = elementMap.erase(it);
|
it = elementMap.erase(it);
|
||||||
//TODO: ? disconnect, unload characters, notify other clients
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
++it;
|
++it;
|
||||||
|
|||||||
@@ -23,35 +23,33 @@
|
|||||||
#define CLIENTMANAGER_HPP_
|
#define CLIENTMANAGER_HPP_
|
||||||
|
|
||||||
#include "client_data.hpp"
|
#include "client_data.hpp"
|
||||||
#include "manager_interface.hpp"
|
|
||||||
#include "server_packet.hpp"
|
#include "server_packet.hpp"
|
||||||
#include "singleton.hpp"
|
#include "singleton.hpp"
|
||||||
|
|
||||||
#include "SDL/SDL_net.h"
|
#include "SDL/SDL_net.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
class ClientManager:
|
class ClientManager: public Singleton<ClientManager> {
|
||||||
public Singleton<ClientManager>,
|
|
||||||
public ManagerInterface<ClientData, IPaddress>
|
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
//methods
|
//methods
|
||||||
int CheckConnections();
|
std::list<int> CheckConnections();
|
||||||
void HandlePong(ServerPacket* const argPacket);
|
void HandlePong(ServerPacket* const argPacket);
|
||||||
|
|
||||||
//common public methods
|
//common public methods
|
||||||
int Create(IPaddress) override;
|
int Create(IPaddress);
|
||||||
void Unload(int uid) override;
|
void Unload(int uid);
|
||||||
|
|
||||||
void UnloadAll() override;
|
void UnloadAll();
|
||||||
void UnloadIf(std::function<bool(std::pair<const int, ClientData>)> fn) override;
|
void UnloadIf(std::function<bool(std::pair<const int, ClientData const&>)> fn);
|
||||||
|
|
||||||
//accessors & mutators
|
//accessors & mutators
|
||||||
ClientData* Get(int uid) override;
|
ClientData* Get(int uid);
|
||||||
int GetLoadedCount() override;
|
int GetLoadedCount();
|
||||||
int GetTotalCount() override;
|
int GetTotalCount();
|
||||||
std::map<int, ClientData>* GetContainer() override;
|
std::map<int, ClientData>* GetContainer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend Singleton<ClientManager>;
|
friend Singleton<ClientManager>;
|
||||||
@@ -59,11 +57,8 @@ private:
|
|||||||
ClientManager() = default;
|
ClientManager() = default;
|
||||||
~ClientManager() = default;
|
~ClientManager() = default;
|
||||||
|
|
||||||
//EMPTY
|
//members
|
||||||
int Load(IPaddress) override { return -1; }
|
std::map<int, ClientData> elementMap;
|
||||||
int Save(int uid) override { return -1; }
|
|
||||||
void Delete(int uid) override { return; }
|
|
||||||
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013-2015
|
|
||||||
*
|
|
||||||
* This software is provided 'as-is', without any express or implied
|
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
|
||||||
* arising from the use of this software.
|
|
||||||
*
|
|
||||||
* Permission is granted to anyone to use this software for any purpose,
|
|
||||||
* including commercial applications, and to alter it and redistribute it
|
|
||||||
* freely, subject to the following restrictions:
|
|
||||||
*
|
|
||||||
* 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
* claim that you wrote the original software. If you use this software
|
|
||||||
* in a product, an acknowledgment in the product documentation would be
|
|
||||||
* appreciated but is not required.
|
|
||||||
*
|
|
||||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
* misrepresented as being the original software.
|
|
||||||
*
|
|
||||||
* 3. This notice may not be removed or altered from any source
|
|
||||||
* distribution.
|
|
||||||
*/
|
|
||||||
#ifndef DOORMANAGER_HPP_
|
|
||||||
#define DOORMANAGER_HPP_
|
|
||||||
|
|
||||||
#include "door_data.hpp"
|
|
||||||
#include "manager_interface.hpp"
|
|
||||||
#include "singleton.hpp"
|
|
||||||
#include "vector2.hpp"
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class DoorManager:
|
|
||||||
public Singleton<DoorManager>,
|
|
||||||
public ManagerInterface<DoorData, std::string, Vector2>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
//common public methods
|
|
||||||
int Create(std::string, Vector2) override;
|
|
||||||
int Load(std::string, Vector2) override;
|
|
||||||
int Save(int uid) override;
|
|
||||||
void Unload(int uid) override;
|
|
||||||
void Delete(int uid) override;
|
|
||||||
|
|
||||||
void UnloadAll() override;
|
|
||||||
void UnloadIf(std::function<bool(std::pair<const int, DoorData>)> fn) override;
|
|
||||||
|
|
||||||
//accessors & mutators
|
|
||||||
DoorData* Get(int uid) override;
|
|
||||||
int GetLoadedCount() override;
|
|
||||||
int GetTotalCount() override;
|
|
||||||
std::map<int, DoorData>* GetContainer() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend Singleton<DoorManager>;
|
|
||||||
|
|
||||||
DoorManager() = default;
|
|
||||||
~DoorManager() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -21,6 +21,14 @@
|
|||||||
*/
|
*/
|
||||||
#include "entity.hpp"
|
#include "entity.hpp"
|
||||||
|
|
||||||
|
Entity::Entity(const char* _type): type(_type) {
|
||||||
|
//EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
void Entity::Update() {
|
||||||
|
origin += motion;
|
||||||
|
}
|
||||||
|
|
||||||
int Entity::SetRoomIndex(int i) {
|
int Entity::SetRoomIndex(int i) {
|
||||||
return roomIndex = i;
|
return roomIndex = i;
|
||||||
}
|
}
|
||||||
@@ -33,14 +41,26 @@ Vector2 Entity::SetMotion(Vector2 v) {
|
|||||||
return motion = v;
|
return motion = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Entity::GetRoomIndex() {
|
BoundingBox Entity::SetBounds(BoundingBox b) {
|
||||||
|
return bounds = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Entity::GetRoomIndex() const {
|
||||||
return roomIndex;
|
return roomIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 Entity::GetOrigin() {
|
Vector2 Entity::GetOrigin() const {
|
||||||
return origin;
|
return origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 Entity::GetMotion() {
|
Vector2 Entity::GetMotion() const {
|
||||||
return motion;
|
return motion;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox Entity::GetBounds() const {
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* Entity::GetType() const {
|
||||||
|
return type;
|
||||||
}
|
}
|
||||||
@@ -22,27 +22,38 @@
|
|||||||
#ifndef ENTITY_HPP_
|
#ifndef ENTITY_HPP_
|
||||||
#define ENTITY_HPP_
|
#define ENTITY_HPP_
|
||||||
|
|
||||||
|
#include "bounding_box.hpp"
|
||||||
#include "vector2.hpp"
|
#include "vector2.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
//The base class for all objects in the world
|
//The base class for all objects in the world
|
||||||
class Entity {
|
class Entity {
|
||||||
public:
|
public:
|
||||||
|
virtual void Update();
|
||||||
|
|
||||||
//accessors & mutators
|
//accessors & mutators
|
||||||
int SetRoomIndex(int i);
|
int SetRoomIndex(int i);
|
||||||
Vector2 SetOrigin(Vector2 v);
|
Vector2 SetOrigin(Vector2 v);
|
||||||
Vector2 SetMotion(Vector2 v);
|
Vector2 SetMotion(Vector2 v);
|
||||||
|
BoundingBox SetBounds(BoundingBox b);
|
||||||
|
|
||||||
int GetRoomIndex();
|
int GetRoomIndex() const;
|
||||||
Vector2 GetOrigin();
|
Vector2 GetOrigin() const;
|
||||||
Vector2 GetMotion();
|
Vector2 GetMotion() const;
|
||||||
|
BoundingBox GetBounds() const;
|
||||||
|
|
||||||
|
const char* GetType() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Entity() = default;
|
Entity(const char*);
|
||||||
~Entity() = default;
|
virtual ~Entity() = default;
|
||||||
|
|
||||||
int roomIndex = -1;
|
int roomIndex = -1;
|
||||||
Vector2 origin;
|
Vector2 origin = {0, 0};
|
||||||
Vector2 motion;
|
Vector2 motion = {0, 0};
|
||||||
|
BoundingBox bounds = {0, 0, 0, 0};
|
||||||
|
const char* type;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "entity_api.hpp"
|
||||||
|
|
||||||
|
#include "entity.hpp"
|
||||||
|
|
||||||
|
static int setRoomIndex(lua_State* L) {
|
||||||
|
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||||
|
entity->SetRoomIndex(lua_tointeger(L, 2));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setOrigin(lua_State* L) {
|
||||||
|
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||||
|
entity->SetOrigin({lua_tonumber(L, 2), lua_tonumber(L, 3)});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setMotion(lua_State* L) {
|
||||||
|
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||||
|
entity->SetMotion({lua_tonumber(L, 2), lua_tonumber(L, 3)});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setBounds(lua_State* L) {
|
||||||
|
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||||
|
entity->SetBounds({
|
||||||
|
lua_tointeger(L, 2),
|
||||||
|
lua_tointeger(L, 3),
|
||||||
|
lua_tointeger(L, 4),
|
||||||
|
lua_tointeger(L, 5)
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getRoomIndex(lua_State* L) {
|
||||||
|
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushinteger(L, entity->GetRoomIndex());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getOrigin(lua_State* L) {
|
||||||
|
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushnumber(L, entity->GetOrigin().x);
|
||||||
|
lua_pushnumber(L, entity->GetOrigin().y);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getMotion(lua_State* L) {
|
||||||
|
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushnumber(L, entity->GetMotion().x);
|
||||||
|
lua_pushnumber(L, entity->GetMotion().y);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getBounds(lua_State* L) {
|
||||||
|
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushinteger(L, entity->GetBounds().x);
|
||||||
|
lua_pushinteger(L, entity->GetBounds().y);
|
||||||
|
lua_pushinteger(L, entity->GetBounds().w);
|
||||||
|
lua_pushinteger(L, entity->GetBounds().h);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getType(lua_State* L) {
|
||||||
|
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushstring(L, entity->GetType());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const luaL_Reg entityLib[] = {
|
||||||
|
{"SetRoomIndex", setRoomIndex},
|
||||||
|
{"SetOrigin", setOrigin},
|
||||||
|
{"SetMotion", setMotion},
|
||||||
|
{"SetBounds", setBounds},
|
||||||
|
{"GetRoomIndex", getRoomIndex},
|
||||||
|
{"GetOrigin", getOrigin},
|
||||||
|
{"GetMotion", getMotion},
|
||||||
|
{"GetBounds", getBounds},
|
||||||
|
{"GetType", getType},
|
||||||
|
{nullptr, nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
|
LUAMOD_API int openEntityAPI(lua_State* L) {
|
||||||
|
luaL_newlib(L, entityLib);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -19,16 +19,12 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef TILESHEETAPI_HPP_
|
#ifndef ENTITYAPI_HPP_
|
||||||
#define TILESHEETAPI_HPP_
|
#define ENTITYAPI_HPP_
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#include "lua.hpp"
|
||||||
#include "lua/lua.hpp"
|
|
||||||
#else
|
|
||||||
#include "lua.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TORTUGA_TILE_SHEET_NAME "tile_sheet"
|
#define TORTUGA_ENTITY_API "entity"
|
||||||
LUAMOD_API int openTileSheetAPI(lua_State* L);
|
LUAMOD_API int openEntityAPI(lua_State* L);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+25
-10
@@ -34,14 +34,20 @@
|
|||||||
#define linit_c
|
#define linit_c
|
||||||
#define LUA_LIB
|
#define LUA_LIB
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#include "lua.hpp"
|
||||||
#include "lua/lua.hpp"
|
|
||||||
#else
|
|
||||||
#include "lua.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "map_system_api.hpp"
|
#include "entity_api.hpp"
|
||||||
#include "room_system_api.hpp"
|
#include "character_api.hpp"
|
||||||
|
#include "character_manager_api.hpp"
|
||||||
|
#include "region_api.hpp"
|
||||||
|
#include "region_pager_api.hpp"
|
||||||
|
#include "monster_api.hpp"
|
||||||
|
#include "monster_manager_api.hpp"
|
||||||
|
#include "network_api.hpp"
|
||||||
|
#include "room_api.hpp"
|
||||||
|
#include "room_manager_api.hpp"
|
||||||
|
#include "trigger_api.hpp"
|
||||||
|
#include "trigger_manager_api.hpp"
|
||||||
|
|
||||||
//these libs are loaded by lua.c and are readily available to any Lua program
|
//these libs are loaded by lua.c and are readily available to any Lua program
|
||||||
static const luaL_Reg loadedlibs[] = {
|
static const luaL_Reg loadedlibs[] = {
|
||||||
@@ -59,11 +65,20 @@ static const luaL_Reg loadedlibs[] = {
|
|||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//these libs are preloaded and must be required before used
|
//these libs are preloaded and must be required before used
|
||||||
static const luaL_Reg preloadedlibs[] = {
|
static const luaL_Reg preloadedlibs[] = {
|
||||||
{TORTUGA_MAP_SYSTEM_API, openMapSystemAPI},
|
{TORTUGA_ENTITY_API, openEntityAPI}, //required by derived classes
|
||||||
{TORTUGA_ROOM_SYSTEM_API, openRoomSystemAPI},
|
{TORTUGA_CHARACTER_API, openCharacterAPI},
|
||||||
|
{TORTUGA_CHARACTER_MANAGER_API, openCharacterManagerAPI},
|
||||||
|
{TORTUGA_MONSTER_API, openMonsterAPI},
|
||||||
|
{TORTUGA_MONSTER_MANAGER_API, openMonsterManagerAPI},
|
||||||
|
{TORTUGA_NETWORK_API, openNetworkAPI},
|
||||||
|
{TORTUGA_REGION_API, openRegionAPI},
|
||||||
|
{TORTUGA_REGION_PAGER_API, openRegionPagerAPI},
|
||||||
|
{TORTUGA_ROOM_API, openRoomAPI},
|
||||||
|
{TORTUGA_ROOM_MANAGER_API, openRoomManagerAPI},
|
||||||
|
{TORTUGA_TRIGGER_API, openTriggerAPI},
|
||||||
|
{TORTUGA_TRIGGER_MANAGER_API, openTriggerManagerAPI},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,6 @@
|
|||||||
#include "character_manager.hpp"
|
#include "character_manager.hpp"
|
||||||
#include "client_manager.hpp"
|
#include "client_manager.hpp"
|
||||||
#include "config_utility.hpp"
|
#include "config_utility.hpp"
|
||||||
#include "door_manager.hpp"
|
|
||||||
#include "monster_manager.hpp"
|
|
||||||
#include "room_manager.hpp"
|
#include "room_manager.hpp"
|
||||||
#include "udp_network_utility.hpp"
|
#include "udp_network_utility.hpp"
|
||||||
|
|
||||||
@@ -43,8 +41,6 @@ int main(int argc, char* argv[]) {
|
|||||||
CharacterManager::CreateSingleton();
|
CharacterManager::CreateSingleton();
|
||||||
ClientManager::CreateSingleton();
|
ClientManager::CreateSingleton();
|
||||||
ConfigUtility::CreateSingleton();
|
ConfigUtility::CreateSingleton();
|
||||||
DoorManager::CreateSingleton();
|
|
||||||
MonsterManager::CreateSingleton();
|
|
||||||
RoomManager::CreateSingleton();
|
RoomManager::CreateSingleton();
|
||||||
UDPNetworkUtility::CreateSingleton();
|
UDPNetworkUtility::CreateSingleton();
|
||||||
|
|
||||||
@@ -63,8 +59,6 @@ int main(int argc, char* argv[]) {
|
|||||||
CharacterManager::DeleteSingleton();
|
CharacterManager::DeleteSingleton();
|
||||||
ClientManager::DeleteSingleton();
|
ClientManager::DeleteSingleton();
|
||||||
ConfigUtility::DeleteSingleton();
|
ConfigUtility::DeleteSingleton();
|
||||||
DoorManager::DeleteSingleton();
|
|
||||||
MonsterManager::DeleteSingleton();
|
|
||||||
RoomManager::DeleteSingleton();
|
RoomManager::DeleteSingleton();
|
||||||
UDPNetworkUtility::DeleteSingleton();
|
UDPNetworkUtility::DeleteSingleton();
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
#include directories
|
#include directories
|
||||||
INCLUDES+=. accounts characters clients doors entities monsters rooms server_utilities ../common/debugging ../common/gameplay ../common/map ../common/network ../common/network/packet_types ../common/utilities
|
INCLUDES+=. accounts characters clients entities monsters rooms server_utilities triggers ../common/debugging ../common/gameplay ../common/map ../common/network ../common/network/packet_types ../common/utilities
|
||||||
|
|
||||||
#libraries
|
#libraries
|
||||||
#the order of the $(LIBS) is important, at least for MinGW
|
#the order of the $(LIBS) is important, at least for MinGW
|
||||||
@@ -28,11 +28,11 @@ all: $(OBJ) $(OUT)
|
|||||||
$(MAKE) -C accounts
|
$(MAKE) -C accounts
|
||||||
$(MAKE) -C characters
|
$(MAKE) -C characters
|
||||||
$(MAKE) -C clients
|
$(MAKE) -C clients
|
||||||
$(MAKE) -C doors
|
|
||||||
$(MAKE) -C entities
|
$(MAKE) -C entities
|
||||||
$(MAKE) -C monsters
|
$(MAKE) -C monsters
|
||||||
$(MAKE) -C rooms
|
$(MAKE) -C rooms
|
||||||
$(MAKE) -C server_utilities
|
$(MAKE) -C server_utilities
|
||||||
|
$(MAKE) -C triggers
|
||||||
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
|
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
|
||||||
|
|
||||||
$(OBJ): | $(OBJDIR)
|
$(OBJ): | $(OBJDIR)
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "monster_api.hpp"
|
||||||
|
|
||||||
|
#include "monster_data.hpp"
|
||||||
|
|
||||||
|
#include "entity_api.hpp"
|
||||||
|
|
||||||
|
static int setAvatar(lua_State* L) {
|
||||||
|
MonsterData* monster = static_cast<MonsterData*>(lua_touserdata(L, 1));
|
||||||
|
monster->SetAvatar(lua_tostring(L, 2));
|
||||||
|
//TODO: send an update to the clients?
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getAvatar(lua_State* L) {
|
||||||
|
MonsterData* monster = static_cast<MonsterData*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushstring(L, monster->GetAvatar().c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setScript(lua_State* L) {
|
||||||
|
MonsterData* monster = static_cast<MonsterData*>(lua_touserdata(L, 1));
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, monster->GetScriptReference());
|
||||||
|
monster->SetScriptReference(luaL_ref(L, LUA_REGISTRYINDEX));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getScript(lua_State* L) {
|
||||||
|
MonsterData* monster = static_cast<MonsterData*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushinteger(L, monster->GetScriptReference());
|
||||||
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const luaL_Reg monsterLib[] = {
|
||||||
|
{"SetAvatar", setAvatar},
|
||||||
|
{"GetAvatar", getAvatar},
|
||||||
|
{"SetScript", setScript},
|
||||||
|
{"GetScript", getScript},
|
||||||
|
{nullptr, nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
|
LUAMOD_API int openMonsterAPI(lua_State* L) {
|
||||||
|
//get the parent table
|
||||||
|
luaL_requiref(L, TORTUGA_ENTITY_API, openEntityAPI, false);
|
||||||
|
|
||||||
|
//the local table
|
||||||
|
luaL_newlib(L, monsterLib);
|
||||||
|
|
||||||
|
//merge the local table into the parent table
|
||||||
|
lua_pushnil(L); //first key
|
||||||
|
while(lua_next(L, -2)) {
|
||||||
|
//copy the key-value pair
|
||||||
|
lua_pushvalue(L, -2);
|
||||||
|
lua_pushvalue(L, -2);
|
||||||
|
|
||||||
|
//push the copy to the parent table
|
||||||
|
lua_settable(L, -6);
|
||||||
|
|
||||||
|
//pop the original value before continuing
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove the local table, leaving the expanded parent table
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#ifndef MONSTERAPI_HPP_
|
||||||
|
#define MONSTERAPI_HPP_
|
||||||
|
|
||||||
|
#include "lua.hpp"
|
||||||
|
|
||||||
|
#define TORTUGA_MONSTER_API "monster"
|
||||||
|
LUAMOD_API int openMonsterAPI(lua_State* L);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -21,18 +21,22 @@
|
|||||||
*/
|
*/
|
||||||
#include "monster_data.hpp"
|
#include "monster_data.hpp"
|
||||||
|
|
||||||
std::string MonsterData::SetAvatar(std::string s) {
|
MonsterData::MonsterData(): Entity("monster") {
|
||||||
return avatar = s;
|
//EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
int MonsterData::SetScriptReference(int i) {
|
std::string MonsterData::SetAvatar(std::string s) {
|
||||||
return scriptRef = i;
|
return avatar = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string MonsterData::GetAvatar() {
|
std::string MonsterData::GetAvatar() {
|
||||||
return avatar;
|
return avatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MonsterData::SetScriptReference(int i) {
|
||||||
|
return scriptRef = i;
|
||||||
|
}
|
||||||
|
|
||||||
int MonsterData::GetScriptReference() {
|
int MonsterData::GetScriptReference() {
|
||||||
return scriptRef;
|
return scriptRef;
|
||||||
}
|
}
|
||||||
@@ -24,24 +24,26 @@
|
|||||||
|
|
||||||
#include "entity.hpp"
|
#include "entity.hpp"
|
||||||
|
|
||||||
|
#include "lua.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class MonsterData: public Entity {
|
class MonsterData: public Entity {
|
||||||
public:
|
public:
|
||||||
MonsterData() = default;
|
MonsterData();
|
||||||
~MonsterData() = default;
|
~MonsterData() = default;
|
||||||
|
|
||||||
std::string SetAvatar(std::string);
|
std::string SetAvatar(std::string);
|
||||||
int SetScriptReference(int);
|
|
||||||
|
|
||||||
std::string GetAvatar();
|
std::string GetAvatar();
|
||||||
|
|
||||||
|
int SetScriptReference(int);
|
||||||
int GetScriptReference();
|
int GetScriptReference();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class MonsterManager;
|
friend class MonsterManager;
|
||||||
|
|
||||||
std::string avatar;
|
std::string avatar;
|
||||||
int scriptRef;
|
int scriptRef = LUA_NOREF;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -21,62 +21,54 @@
|
|||||||
*/
|
*/
|
||||||
#include "monster_manager.hpp"
|
#include "monster_manager.hpp"
|
||||||
|
|
||||||
|
MonsterManager::MonsterManager() {
|
||||||
|
//EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
MonsterManager::~MonsterManager() {
|
||||||
|
UnloadAll();
|
||||||
|
}
|
||||||
|
|
||||||
int MonsterManager::Create(std::string) {
|
int MonsterManager::Create(std::string) {
|
||||||
//TODO
|
//TODO: (9) MonsterManager::Create()
|
||||||
}
|
|
||||||
|
|
||||||
int MonsterManager::Load(std::string) {
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
int MonsterManager::Save(int uid) {
|
|
||||||
//TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MonsterManager::Unload(int uid) {
|
void MonsterManager::Unload(int uid) {
|
||||||
//TODO
|
//TODO: (9) MonsterManager::Unload()
|
||||||
}
|
|
||||||
|
|
||||||
void MonsterManager::Delete(int uid) {
|
|
||||||
//TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MonsterManager::UnloadAll() {
|
void MonsterManager::UnloadAll() {
|
||||||
//TODO
|
//TODO: (9) MonsterManager::UnloadAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
void MonsterManager::UnloadIf(std::function<bool(std::pair<const int, MonsterData>)> fn) {
|
void MonsterManager::UnloadIf(std::function<bool(std::pair<const int, MonsterData const&>)> fn) {
|
||||||
//TODO
|
//TODO: (9) MonsterManager::UnloadIf()
|
||||||
}
|
}
|
||||||
|
|
||||||
MonsterData* MonsterManager::Get(int uid) {
|
MonsterData* MonsterManager::Get(int uid) {
|
||||||
//TODO
|
//TODO: (9) MonsterManager::Get()
|
||||||
}
|
}
|
||||||
|
|
||||||
int MonsterManager::GetLoadedCount() {
|
int MonsterManager::GetLoadedCount() {
|
||||||
//TODO
|
//TODO: (9) MonsterManager::GetLoadedCount()
|
||||||
}
|
|
||||||
|
|
||||||
int MonsterManager::GetTotalCount() {
|
|
||||||
//TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<int, MonsterData>* MonsterManager::GetContainer() {
|
std::map<int, MonsterData>* MonsterManager::GetContainer() {
|
||||||
//TODO
|
//TODO: (9) MonsterManager::GetContainer()
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3* MonsterManager::SetDatabase(sqlite3* db) {
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3* MonsterManager::GetDatabase() {
|
|
||||||
//TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_State* MonsterManager::SetLuaState(lua_State* L) {
|
lua_State* MonsterManager::SetLuaState(lua_State* L) {
|
||||||
//TODO
|
//TODO: (9) MonsterManager::SetLuaState()
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_State* MonsterManager::GetLuaState() {
|
lua_State* MonsterManager::GetLuaState() {
|
||||||
//TODO
|
//TODO: (9) MonsterManager::GetLuaState()
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3* MonsterManager::SetDatabase(sqlite3* db) {
|
||||||
|
//TODO: (9) MonsterManager::SetDatabase()
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3* MonsterManager::GetDatabase() {
|
||||||
|
//TODO: (9) MonsterManager::GetDatabase()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,56 +22,43 @@
|
|||||||
#ifndef MONSTERMANAGER_HPP_
|
#ifndef MONSTERMANAGER_HPP_
|
||||||
#define MONSTERMANAGER_HPP_
|
#define MONSTERMANAGER_HPP_
|
||||||
|
|
||||||
#include "manager_interface.hpp"
|
|
||||||
#include "monster_data.hpp"
|
#include "monster_data.hpp"
|
||||||
#include "singleton.hpp"
|
|
||||||
|
|
||||||
#ifdef __unix__
|
#include "lua.hpp"
|
||||||
#include "lua.hpp"
|
#include "sqlite3.h"
|
||||||
#include "sqlite3.h"
|
|
||||||
#else
|
|
||||||
#include "lua/lua.hpp"
|
|
||||||
#include "sqlite3/sqlite3.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class MonsterManager:
|
class MonsterManager {
|
||||||
public Singleton<MonsterManager>,
|
|
||||||
public ManagerInterface<MonsterData, std::string>
|
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
//common public methods
|
MonsterManager();
|
||||||
int Create(std::string) override;
|
~MonsterManager();
|
||||||
int Load(std::string) override;
|
|
||||||
int Save(int uid) override;
|
|
||||||
void Unload(int uid) override;
|
|
||||||
void Delete(int uid) override;
|
|
||||||
|
|
||||||
void UnloadAll() override;
|
//common public methods
|
||||||
void UnloadIf(std::function<bool(std::pair<const int, MonsterData>)> fn) override;
|
int Create(std::string);
|
||||||
|
void Unload(int uid);
|
||||||
|
|
||||||
|
void UnloadAll();
|
||||||
|
void UnloadIf(std::function<bool(std::pair<const int, MonsterData const&>)> fn);
|
||||||
|
|
||||||
//accessors & mutators
|
//accessors & mutators
|
||||||
MonsterData* Get(int uid) override;
|
MonsterData* Get(int uid);
|
||||||
int GetLoadedCount() override;
|
int GetLoadedCount();
|
||||||
int GetTotalCount() override;
|
std::map<int, MonsterData>* GetContainer();
|
||||||
std::map<int, MonsterData>* GetContainer() override;
|
|
||||||
|
|
||||||
//hooks
|
//hooks
|
||||||
sqlite3* SetDatabase(sqlite3* db);
|
|
||||||
sqlite3* GetDatabase();
|
|
||||||
lua_State* SetLuaState(lua_State* L);
|
lua_State* SetLuaState(lua_State* L);
|
||||||
lua_State* GetLuaState();
|
lua_State* GetLuaState();
|
||||||
|
sqlite3* SetDatabase(sqlite3* db);
|
||||||
|
sqlite3* GetDatabase();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend Singleton<MonsterManager>;
|
//members
|
||||||
|
std::map<int, MonsterData> elementMap;
|
||||||
MonsterManager() = default;
|
|
||||||
~MonsterManager() = default;
|
|
||||||
|
|
||||||
sqlite3* database = nullptr;
|
|
||||||
lua_State* lua = nullptr;
|
lua_State* lua = nullptr;
|
||||||
|
sqlite3* database = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "monster_manager_api.hpp"
|
||||||
|
|
||||||
|
#include "monster_manager.hpp"
|
||||||
|
|
||||||
|
static const luaL_Reg monsterManagerLib[] = {
|
||||||
|
{nullptr, nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
|
LUAMOD_API int openMonsterManagerAPI(lua_State* L) {
|
||||||
|
luaL_newlib(L, monsterManagerLib);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#ifndef MONSTERMANAGERAPI_HPP_
|
||||||
|
#define MONSTERMANAGERAPI_HPP_
|
||||||
|
|
||||||
|
#include "lua.hpp"
|
||||||
|
|
||||||
|
#define TORTUGA_MONSTER_MANAGER_API "monster_manager"
|
||||||
|
LUAMOD_API int openMonsterManagerAPI(lua_State* L);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "network_api.hpp"
|
||||||
|
|
||||||
|
#include "character_data.hpp"
|
||||||
|
#include "character_manager.hpp"
|
||||||
|
#include "server_utilities.hpp"
|
||||||
|
|
||||||
|
static int pumpCharacterUpdate(lua_State* L) {
|
||||||
|
CharacterData* characterData = static_cast<CharacterData*>(lua_touserdata(L, 1));
|
||||||
|
|
||||||
|
//determine the character's index
|
||||||
|
int index = -1;
|
||||||
|
for (auto const& it : *CharacterManager::GetSingleton().GetContainer()) {
|
||||||
|
if(characterData == &it.second) {
|
||||||
|
index = it.first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//signal an error
|
||||||
|
if (index == -1) {
|
||||||
|
lua_pushboolean(L, false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//fill the packet with all of this character's data
|
||||||
|
CharacterPacket newPacket;
|
||||||
|
newPacket.type = SerialPacketType::CHARACTER_UPDATE;
|
||||||
|
newPacket.characterIndex = index;
|
||||||
|
strncpy(newPacket.handle, characterData->GetHandle().c_str(), PACKET_STRING_SIZE);
|
||||||
|
strncpy(newPacket.avatar, characterData->GetAvatar().c_str(), PACKET_STRING_SIZE);
|
||||||
|
newPacket.accountIndex = characterData->GetOwner();
|
||||||
|
newPacket.roomIndex = characterData->GetRoomIndex();
|
||||||
|
newPacket.origin = characterData->GetOrigin();
|
||||||
|
newPacket.motion = characterData->GetMotion();
|
||||||
|
|
||||||
|
//pump to the room
|
||||||
|
pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
|
||||||
|
|
||||||
|
//signal success
|
||||||
|
lua_pushboolean(L, true);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const luaL_Reg networkLib[] = {
|
||||||
|
{"PumpCharacterUpdate", pumpCharacterUpdate},
|
||||||
|
{nullptr, nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
|
LUAMOD_API int openNetworkAPI(lua_State* L) {
|
||||||
|
luaL_newlib(L, networkLib);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user