More multiprotocol support

This commit is contained in:
Eduardo Bart
2012-07-26 03:10:28 -03:00
parent e393bc245d
commit c795eb91ab
43 changed files with 421 additions and 341 deletions

View File

@@ -37,14 +37,14 @@ static const std::string glslMainWithTexCoordsVertexShader = "\n\
void main()\n\
{\n\
gl_Position = calculatePosition();\n\
v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1)).xy;\n\
v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1.0)).xy;\n\
}\n";
static std::string glslPositionOnlyVertexShader = "\n\
attribute highp vec2 a_Vertex;\n\
uniform highp mat3 u_ProjectionMatrix;\n\
highp vec4 calculatePosition() {\n\
return vec4(u_ProjectionMatrix * vec3(a_Vertex.xy, 1), 1);\n\
return vec4(u_ProjectionMatrix * vec3(a_Vertex.xy, 1.0), 1.0);\n\
}\n";
static const std::string glslMainFragmentShader = "\n\

View File

@@ -336,6 +336,7 @@ void Application::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIWidget>("getChildByIndex", &UIWidget::getChildByIndex);
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildById", &UIWidget::recursiveGetChildById);
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildByPos", &UIWidget::recursiveGetChildByPos);
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildren", &UIWidget::recursiveGetChildren);
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildrenByPos", &UIWidget::recursiveGetChildrenByPos);
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildrenByMarginPos", &UIWidget::recursiveGetChildrenByMarginPos);
g_lua.bindClassMemberFunction<UIWidget>("backwardsGetWidgetById", &UIWidget::backwardsGetWidgetById);

View File

@@ -56,7 +56,7 @@ private:
SoundSourcePtr createSoundSource(const std::string& filename);
uint loadFileIntoBuffer(const SoundFilePtr& soundFile);
std::map<std::string, SoundBufferPtr> m_buffers;
std::unordered_map<std::string, SoundBufferPtr> m_buffers;
std::vector<SoundSourcePtr> m_sources;
SoundSourcePtr m_musicSource;
ALCdevice *m_device;

View File

@@ -81,7 +81,7 @@ protected:
private:
bool updateWidget(const UIWidgetPtr& widget, UIAnchorGroup& anchorGroup, UIWidgetPtr first = nullptr);
std::map<UIWidgetPtr, UIAnchorGroup> m_anchorsGroups;
std::unordered_map<UIWidgetPtr, UIAnchorGroup> m_anchorsGroups;
};
#endif

View File

@@ -1130,6 +1130,18 @@ UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos, bool wantsPh
return nullptr;
}
UIWidgetList UIWidget::recursiveGetChildren()
{
UIWidgetList children;
for(const UIWidgetPtr& child : m_children) {
UIWidgetList subChildren = child->recursiveGetChildren();
if(!subChildren.empty())
children.insert(children.end(), subChildren.begin(), subChildren.end());
children.push_back(child);
}
return children;
}
UIWidgetList UIWidget::recursiveGetChildrenByPos(const Point& childPos)
{
UIWidgetList children;

View File

@@ -147,6 +147,7 @@ public:
UIWidgetPtr getChildByIndex(int index);
UIWidgetPtr recursiveGetChildById(const std::string& id);
UIWidgetPtr recursiveGetChildByPos(const Point& childPos, bool wantsPhantom);
UIWidgetList recursiveGetChildren();
UIWidgetList recursiveGetChildrenByPos(const Point& childPos);
UIWidgetList recursiveGetChildrenByMarginPos(const Point& childPos);
UIWidgetPtr backwardsGetWidgetById(const std::string& id);

View File

@@ -79,7 +79,7 @@ public:
uint8 getSkull() { return m_skull; }
uint8 getShield() { return m_shield; }
uint8 getEmblem() { return m_emblem; }
bool getPassable() { return m_passable; }
bool isPassable() { return m_passable; }
Point getDrawOffset();
Point getWalkOffset() { return m_walkOffset; }

View File

@@ -39,15 +39,16 @@ Game::Game()
{
resetGameStates();
m_protocolVersion = 0;
setProtocolVersion(PROTOCOL);
}
void Game::resetGameStates()
{
m_online = false;
m_denyBotCall = false;
m_dead = false;
m_mounted = false;
m_serverBeat = 50;
m_seq = 0;
m_canReportBugs = false;
m_fightMode = Otc::FightBalanced;
m_chaseMode = Otc::DontChase;
@@ -104,15 +105,9 @@ void Game::processLoginWait(const std::string& message, int time)
g_lua.callGlobalField("g_game", "onLoginWait", message, time);
}
void Game::processGameStart(const LocalPlayerPtr& localPlayer, int serverBeat, bool canReportBugs)
void Game::processGameStart()
{
// reset the new game state
resetGameStates();
m_localPlayer = localPlayer;
m_localPlayer->setName(m_characterName);
m_serverBeat = serverBeat;
m_canReportBugs = canReportBugs;
m_online = true;
// synchronize fight modes with the server
m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight);
@@ -401,9 +396,9 @@ void Game::processQuestLine(int questId, const std::vector<std::tuple<std::strin
g_lua.callGlobalField("g_game", "onQuestLine", questId, questMissions);
}
void Game::processAttackCancel()
void Game::processAttackCancel(uint seq)
{
if(isAttacking())
if(isAttacking() && (seq == 0 || m_seq == seq))
setAttackingCreature(nullptr);
}
@@ -423,6 +418,12 @@ void Game::loginWorld(const std::string& account, const std::string& password, c
if(m_protocolVersion == 0)
stdext::throw_exception("Must set a valid game protocol version before logging.");
// reset the new game state
resetGameStates();
m_localPlayer = LocalPlayerPtr(new LocalPlayer);
m_localPlayer->setName(m_characterName);
m_protocolGame = ProtocolGamePtr(new ProtocolGame);
m_protocolGame->login(account, password, worldHost, (uint16)worldPort, characterName);
m_characterName = characterName;
@@ -505,15 +506,10 @@ void Game::autoWalk(const std::vector<Otc::Direction>& dirs)
Otc::Direction direction = dirs.front();
TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction));
if(toTile && toTile->isWalkable())
if(toTile && toTile->isWalkable() && !m_localPlayer->isAutoWalking())
m_localPlayer->preWalk(direction);
forceWalk(direction);
std::vector<Otc::Direction> nextDirs = dirs;
nextDirs.erase(nextDirs.begin());
if(nextDirs.size() > 0)
m_protocolGame->sendAutoWalk(nextDirs);
m_protocolGame->sendAutoWalk(dirs);
g_lua.callGlobalField("g_game", "onAutoWalk", direction);
}
@@ -737,7 +733,7 @@ void Game::attack(const CreaturePtr& creature)
cancelFollow();
setAttackingCreature(creature);
m_protocolGame->sendAttack(creature ? creature->getId() : 0);
m_protocolGame->sendAttack(creature ? creature->getId() : 0, ++m_seq);
}
void Game::follow(const CreaturePtr& creature)
@@ -751,7 +747,7 @@ void Game::follow(const CreaturePtr& creature)
cancelAttack();
setFollowingCreature(creature);
m_protocolGame->sendFollow(creature ? creature->getId() : 0);
m_protocolGame->sendFollow(creature ? creature->getId() : 0, ++m_seq);
}
void Game::cancelAttackAndFollow()
@@ -885,7 +881,7 @@ void Game::partyShareExperience(bool active)
{
if(!canPerformGameAction())
return;
m_protocolGame->sendShareExperience(active, 0);
m_protocolGame->sendShareExperience(active);
}
void Game::requestOutfit()
@@ -1084,15 +1080,16 @@ bool Game::checkBotProtection()
bool Game::canPerformGameAction()
{
// we can only perform game actions if we meet these conditions:
// - the game is online
// - the local player exists
// - the local player is not dead
// - we have a game protocol
// - the game protocol is connected
// - its not a bot action
return m_localPlayer && !m_dead && m_protocolGame && m_protocolGame->isConnected() && checkBotProtection();
return m_online && m_localPlayer && !m_dead && m_protocolGame && m_protocolGame->isConnected() && checkBotProtection();
}
void Game::setProtocolVersion(int version)
void Game::setClientVersion(int version)
{
if(isOnline())
stdext::throw_exception("Unable to change client version while online");
@@ -1147,6 +1144,8 @@ void Game::setProtocolVersion(int version)
}
m_protocolVersion = version;
g_lua.callGlobalField("g_game", "onClientVersionChange", version);
}
void Game::setAttackingCreature(const CreaturePtr& creature)

View File

@@ -48,7 +48,7 @@ protected:
void processLoginAdvice(const std::string& message);
void processLoginWait(const std::string& message, int time);
void processGameStart(const LocalPlayerPtr& localPlayer, int serverBeat, bool canReportBugs);
void processGameStart();
void processGameEnd();
void processDeath(int penality);
@@ -56,7 +56,7 @@ protected:
void processInventoryChange(int slot, const ItemPtr& item);
void processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos);
void processCreatureTeleport(const CreaturePtr& creature);
void processAttackCancel();
void processAttackCancel(uint seq);
void processWalkCancel(Otc::Direction direction);
// message related
@@ -232,17 +232,16 @@ public:
void setFeature(Otc::GameFeature feature) { m_features.set(feature, false); }
bool getFeature(Otc::GameFeature feature) { return m_features.test(feature); }
void setProtocolVersion(int version);
int getProtocolVersion() { return m_protocolVersion; }
void setClientVersion(int version);
int getClientVersion() { return m_protocolVersion; }
void setRSA(const std::string& rsa);
std::string getRSA() { return m_rsa; }
bool canPerformGameAction();
bool canReportBugs() { return m_canReportBugs; }
bool checkBotProtection();
bool isOnline() { return !!m_localPlayer; }
bool isOnline() { return m_online; }
bool isDead() { return m_dead; }
bool isAttacking() { return !!m_attackingCreature; }
bool isFollowing() { return !!m_followingCreature; }
@@ -253,7 +252,10 @@ public:
std::map<int, Vip> getVips() { return m_vips; }
CreaturePtr getAttackingCreature() { return m_attackingCreature; }
CreaturePtr getFollowingCreature() { return m_followingCreature; }
void setServerBeat(int beat) { m_serverBeat = beat; }
int getServerBeat() { return m_serverBeat; }
void setCanReportBugs(bool enable) { m_canReportBugs = enable; }
bool canReportBugs() { return m_canReportBugs; }
LocalPlayerPtr getLocalPlayer() { return m_localPlayer; }
ProtocolGamePtr getProtocolGame() { return m_protocolGame; }
std::string getCharacterName() { return m_characterName; }
@@ -275,10 +277,12 @@ private:
std::map<int, ContainerPtr> m_containers;
std::map<int, Vip> m_vips;
bool m_online;
bool m_denyBotCall;
bool m_dead;
bool m_mounted;
int m_serverBeat;
uint m_seq;
Otc::FightModes m_fightMode;
Otc::ChaseModes m_chaseMode;
bool m_safeFight;

View File

@@ -187,8 +187,8 @@ void Item::setOtbId(uint16 id)
{
if(!g_things.isValidOtbId(id))
id = 0;
auto otbType = g_things.getItemType(id);
m_id = otbType->getClientId();
auto itemType = g_things.getItemType(id);
m_id = itemType->getClientId();
m_otbId = id;
}

View File

@@ -194,8 +194,8 @@ void OTClient::registerLuaFunctions()
g_lua.bindSingletonFunction("g_game", "getServerBeat", &Game::getServerBeat, &g_game);
g_lua.bindSingletonFunction("g_game", "getLocalPlayer", &Game::getLocalPlayer, &g_game);
g_lua.bindSingletonFunction("g_game", "getProtocolGame", &Game::getProtocolGame, &g_game);
g_lua.bindSingletonFunction("g_game", "getProtocolVersion", &Game::getProtocolVersion, &g_game);
g_lua.bindSingletonFunction("g_game", "setProtocolVersion", &Game::setProtocolVersion, &g_game);
g_lua.bindSingletonFunction("g_game", "getClientVersion", &Game::getClientVersion, &g_game);
g_lua.bindSingletonFunction("g_game", "setClientVersion", &Game::setClientVersion, &g_game);
g_lua.bindSingletonFunction("g_game", "getCharacterName", &Game::getCharacterName, &g_game);
g_lua.bindSingletonFunction("g_game", "getWorldName", &Game::getWorldName, &g_game);
g_lua.bindSingletonFunction("g_game", "getGMActions", &Game::getGMActions, &g_game);

View File

@@ -518,7 +518,7 @@ void Map::saveOtcm(const std::string& fileName)
// version 1 header
fin->addString("OTCM 1.0"); // map description
fin->addU32(g_things.getDatSignature());
fin->addU16(g_game.getProtocolVersion());
fin->addU16(g_game.getClientVersion());
fin->addString(g_game.getWorldName());
// go back and rewrite where the map data starts

View File

@@ -175,7 +175,7 @@ public:
private:
TileMap m_tiles;
std::map<uint32, CreaturePtr> m_knownCreatures;
std::unordered_map<uint32, CreaturePtr> m_knownCreatures;
std::array<std::vector<MissilePtr>, Otc::MAX_Z+1> m_floorMissiles;
std::vector<AnimatedTextPtr> m_animatedTexts;
std::vector<StaticTextPtr> m_staticTexts;

View File

@@ -81,6 +81,6 @@ void OTClient::terminate()
{
g_map.terminate();
g_things.terminate();
g_sprites.termiante();
g_sprites.terminate();
g_shaders.terminate();
}

View File

@@ -135,7 +135,8 @@ namespace Proto {
GameServerMarketEnter = 246, // 944
GameServerMarketLeave = 247, // 944
GameServerMarketDetail = 248, // 944
GameServerMarketBrowse = 249 // 944
GameServerMarketBrowse = 249, // 944
GameServerShowModalDialog = 250 // 960
};
enum ClientOpcodes {

View File

@@ -44,8 +44,7 @@ void ProtocolGame::onConnect()
{
Protocol::onConnect();
// must create local player before parsing anything
m_localPlayer = LocalPlayerPtr(new LocalPlayer);
m_localPlayer = g_game.getLocalPlayer();
if(g_game.getFeature(Otc::GameProtocolChecksum))
enableChecksum();

View File

@@ -79,14 +79,14 @@ public:
void sendOpenPrivateChannel(const std::string& receiver);
void sendCloseNpcChannel();
void sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight);
void sendAttack(uint creatureId);
void sendFollow(uint creatureId);
void sendAttack(uint creatureId, uint seq);
void sendFollow(uint creatureId, uint seq);
void sendInviteToParty(uint creatureId);
void sendJoinParty(uint creatureId);
void sendRevokeInvitation(uint creatureId);
void sendPassLeadership(uint creatureId);
void sendLeaveParty();
void sendShareExperience(bool active, int unknown);
void sendShareExperience(bool active);
void sendOpenOwnChannel();
void sendInviteToOwnChannel(const std::string& name);
void sendExcludeFromOwnChannel(const std::string& name);
@@ -166,9 +166,9 @@ private:
void parsePlayerSkills(const InputMessagePtr& msg);
void parsePlayerState(const InputMessagePtr& msg);
void parsePlayerCancelAttack(const InputMessagePtr& msg);
void parseSpellDelay(const InputMessagePtr& msg);
void parseSpellGroupDelay(const InputMessagePtr& msg);
void parseMultiUseDelay(const InputMessagePtr& msg);
void parseSpellCooldown(const InputMessagePtr& msg);
void parseSpellGroupCooldown(const InputMessagePtr& msg);
void parseMultiUseCooldown(const InputMessagePtr& msg);
void parseCreatureSpeak(const InputMessagePtr& msg);
void parseChannelList(const InputMessagePtr& msg);
void parseOpenChannel(const InputMessagePtr& msg);
@@ -198,15 +198,17 @@ private:
void parseChannelEvent(const InputMessagePtr& msg);
void parseItemInfo(const InputMessagePtr& msg);
void parsePlayerInventory(const InputMessagePtr& msg);
void parseShowModalDialog(const InputMessagePtr& msg);
void parseExtendedOpcode(const InputMessagePtr& msg);
public:
void setMapDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height);
int setFloorDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height, int offset, int skip);
void setTileDescription(const InputMessagePtr& msg, Position position);
int setTileDescription(const InputMessagePtr& msg, Position position);
Outfit getOutfit(const InputMessagePtr& msg);
ThingPtr getThing(const InputMessagePtr& msg);
ThingPtr getMappedThing(const InputMessagePtr& msg);
CreaturePtr getCreature(const InputMessagePtr& msg, int type = 0);
ItemPtr getItem(const InputMessagePtr& msg, int id = 0);
Position getPosition(const InputMessagePtr& msg);

View File

@@ -35,13 +35,18 @@
void ProtocolGame::parseMessage(const InputMessagePtr& msg)
{
int opcode = 0;
int prevOpcode = 0;
int opcode = -1;
int prevOpcode = -1;
try {
while(!msg->eof()) {
opcode = msg->getU8();
if(!m_gameInitialized && opcode >= Proto::GameServerFirstGameOpcode) {
g_game.processGameStart();
m_gameInitialized = true;
}
// try to parse in lua first
int readPos = msg->getReadPos();
if(callLuaField<bool>("onOpcode", opcode, msg))
@@ -49,9 +54,6 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
else
msg->setReadPos(readPos); // restore read pos
if(!m_gameInitialized && opcode > Proto::GameServerFirstGameOpcode)
g_logger.warning("received a game opcode from the server, but the game is not initialized yet, this is a server side bug");
switch(opcode) {
case Proto::GameServerInitGame:
parseInitGame(msg);
@@ -70,8 +72,8 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
break;
case Proto::GameServerPing:
case Proto::GameServerPingBack:
if((opcode == Proto::GameServerPing && g_game.getProtocolVersion() >= 953) ||
(opcode == Proto::GameServerPingBack && g_game.getProtocolVersion() < 953))
if((opcode == Proto::GameServerPing && g_game.getClientVersion() >= 953) ||
(opcode == Proto::GameServerPingBack && g_game.getClientVersion() < 953))
parsePingBack(msg);
else
parsePing(msg);
@@ -279,13 +281,13 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
break;
// PROTOCOL>=870
case Proto::GameServerSpellDelay:
parseSpellDelay(msg);
parseSpellCooldown(msg);
break;
case Proto::GameServerSpellGroupDelay:
parseSpellGroupDelay(msg);
parseSpellGroupCooldown(msg);
break;
case Proto::GameServerMultiUseDelay:
parseMultiUseDelay(msg);
parseMultiUseCooldown(msg);
break;
// PROTOCOL>=910
case Proto::GameServerChannelEvent:
@@ -306,7 +308,7 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
parseExtendedOpcode(msg);
break;
default:
stdext::throw_exception("unknown opcode");
stdext::throw_exception(stdext::format("unhandled opcode %d", (int)opcode));
break;
}
prevOpcode = opcode;
@@ -319,13 +321,13 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
void ProtocolGame::parseInitGame(const InputMessagePtr& msg)
{
m_gameInitialized = true;
uint playerId = msg->getU32();
int serverBeat = msg->getU16();
bool canReportBugs = msg->getU8();
m_localPlayer->setId(playerId);
g_game.processGameStart(m_localPlayer, serverBeat, canReportBugs);
g_game.setServerBeat(serverBeat);
g_game.setCanReportBugs(canReportBugs);
}
void ProtocolGame::parseGMActions(const InputMessagePtr& msg)
@@ -334,9 +336,9 @@ void ProtocolGame::parseGMActions(const InputMessagePtr& msg)
int numViolationReasons;
if(g_game.getProtocolVersion() >= 860)
if(g_game.getClientVersion() >= 860)
numViolationReasons = 20;
else if(g_game.getProtocolVersion() >= 854)
else if(g_game.getClientVersion() >= 854)
numViolationReasons = 19;
else
numViolationReasons = 32;
@@ -454,7 +456,7 @@ void ProtocolGame::parseTileAddThing(const InputMessagePtr& msg)
Position pos = getPosition(msg);
int stackPos = -1;
if(g_game.getProtocolVersion() >= 854)
if(g_game.getClientVersion() >= 854)
stackPos = msg->getU8();
ThingPtr thing = getThing(msg);
@@ -463,54 +465,54 @@ void ProtocolGame::parseTileAddThing(const InputMessagePtr& msg)
void ProtocolGame::parseTileTransformThing(const InputMessagePtr& msg)
{
Position pos = getPosition(msg);
int stackPos = msg->getU8();
ThingPtr thing = getMappedThing(msg);
ThingPtr newThing = getThing(msg);
ThingPtr thing = getThing(msg);
if(thing) {
if(!g_map.removeThingByPos(pos, stackPos))
g_logger.traceError("could not remove thing");
g_map.addThing(thing, pos, stackPos);
if(!thing) {
g_logger.traceError("no thing");
return;
}
Position pos = thing->getPosition();
int stackpos = thing->getStackpos();
assert(thing->getStackPriority() == newThing->getStackPriority());
if(!g_map.removeThing(thing)) {
g_logger.traceError("unable to remove thing");
return;
}
g_map.addThing(newThing, pos, stackpos);
}
void ProtocolGame::parseTileRemoveThing(const InputMessagePtr& msg)
{
Position pos = getPosition(msg);
int stackPos = msg->getU8();
ThingPtr thing = getMappedThing(msg);
if(!thing) {
g_logger.traceError("no thing");
return;
}
if(!g_map.removeThingByPos(pos, stackPos))
g_logger.traceError("could not remove thing");
g_map.removeThing(thing);
}
void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg)
{
Position oldPos = getPosition(msg);
int oldStackpos = msg->getU8();
ThingPtr thing = getMappedThing(msg);
Position newPos = getPosition(msg);
ThingPtr thing = g_map.getThing(oldPos, oldStackpos);
if(!thing) {
g_logger.traceError("could not get thing");
if(!thing || !thing->isCreature()) {
g_logger.traceError("no creature found to move");
return;
}
CreaturePtr creature = thing->asCreature();
if(!creature) {
g_logger.traceError("thing is not a creature");
return;
}
// update map tiles
if(!g_map.removeThing(thing))
g_logger.traceError("could not remove thing");
int stackPos = -2;
// older protocols stores creatures in reverse order
if(!g_game.getProtocolVersion() >= 854)
// newer protocols stores creatures in reverse order
if(!g_game.getClientVersion() >= 854)
stackPos = -1;
g_map.removeThing(thing);
g_map.addThing(thing, newPos, stackPos);
}
@@ -887,7 +889,7 @@ void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
m_localPlayer->setStamina(stamina);
m_localPlayer->setSoul(soul);
if(g_game.getProtocolVersion() >= 910)
if(g_game.getClientVersion() >= 910)
m_localPlayer->setSpeed(msg->getU16());
if(g_game.getFeature(Otc::GamePlayerRegenerationTime))
@@ -918,29 +920,28 @@ void ProtocolGame::parsePlayerState(const InputMessagePtr& msg)
void ProtocolGame::parsePlayerCancelAttack(const InputMessagePtr& msg)
{
if(g_game.getProtocolVersion() >= 860)
msg->getU32(); // unknown
uint seq = 0;
if(g_game.getClientVersion() >= 860)
seq = msg->getU32();
g_game.processAttackCancel();
g_game.processAttackCancel(seq);
}
void ProtocolGame::parseSpellDelay(const InputMessagePtr& msg)
void ProtocolGame::parseSpellCooldown(const InputMessagePtr& msg)
{
msg->getU16(); // spell id
msg->getU16(); // cooldown
msg->getU8(); // unknown
msg->getU32(); // cooldown
}
void ProtocolGame::parseSpellGroupDelay(const InputMessagePtr& msg)
void ProtocolGame::parseSpellGroupCooldown(const InputMessagePtr& msg)
{
msg->getU16(); // spell id
msg->getU16(); // cooldown
msg->getU8(); // unknown
msg->getU8(); // group id
msg->getU32(); // cooldown
}
void ProtocolGame::parseMultiUseDelay(const InputMessagePtr& msg)
void ProtocolGame::parseMultiUseCooldown(const InputMessagePtr& msg)
{
//TODO
msg->getU32(); // cooldown
}
void ProtocolGame::parseCreatureSpeak(const InputMessagePtr& msg)
@@ -1225,18 +1226,36 @@ void ProtocolGame::parseChannelEvent(const InputMessagePtr& msg)
void ProtocolGame::parseItemInfo(const InputMessagePtr& msg)
{
/*int count = msg.getU16() - 1;
for(int i = 0; i < count; i++)
{
int unknown1 = msg->getU8();
int unknown2 = msg->getU16();
std::string unknown3 = msg->getString();
}*/
int size = msg->getU8();
for(int i=0;i<size;++i) {
msg->getU16(); // id
msg->getU8(); // subtype
msg->getString(); // description
}
}
void ProtocolGame::parsePlayerInventory(const InputMessagePtr& msg)
{
//TODO
int size = msg->getU16();
for(int i=0;i<size;++i) {
msg->getU16(); // id
msg->getU8(); // subtype
msg->getU16(); // count
}
}
void ProtocolGame::parseShowModalDialog(const InputMessagePtr& msg)
{
msg->getU32(); // id
msg->getString(); // title
msg->getString(); // message
int size = msg->getU8();
for(int i=0;i<size;++i) {
msg->getString(); // button name
msg->getU8(); // button value
}
msg->getU8(); // default escape button
msg->getU8(); // default enter button
}
void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg)
@@ -1275,51 +1294,41 @@ int ProtocolGame::setFloorDescription(const InputMessagePtr& msg, int x, int y,
for(int nx = 0; nx < width; nx++) {
for(int ny = 0; ny < height; ny++) {
Position tilePos(x + nx + offset, y + ny + offset, z);
// clean pre stored tiles
g_map.cleanTile(tilePos);
if(skip == 0) {
int tileOpt = msg->peekU16();
if(tileOpt >= 0xFF00)
skip = (msg->getU16() & 0xFF);
else {
setTileDescription(msg, tilePos);
skip = (msg->getU16() & 0xFF);
}
}
else
if(skip == 0)
skip = setTileDescription(msg, tilePos);
else {
g_map.cleanTile(tilePos);
skip--;
}
}
}
return skip;
}
void ProtocolGame::setTileDescription(const InputMessagePtr& msg, Position position)
int ProtocolGame::setTileDescription(const InputMessagePtr& msg, Position position)
{
if(g_game.getFeature(Otc::GameEnvironmentEffect))
msg->getU16(); // environment effect
g_map.cleanTile(position);
int stackPos = 0;
while(true) {
int inspectItemId = msg->peekU16();
if(inspectItemId >= 0xFF00) {
return;
}
else {
if(stackPos >= 10)
g_logger.traceError(stdext::format("too many things, stackpos=%d, pos=%s", stackPos, stdext::to_string(position)));
bool gotEffect = 0;
for(int stackPos=0;stackPos<256;stackPos++) {
if(msg->peekU16() >= 0xff00)
return msg->getU16() & 0xff;
ThingPtr thing = getThing(msg);
g_map.addThing(thing, position, -2);
if(g_game.getFeature(Otc::GameEnvironmentEffect) && !gotEffect) {
msg->getU16(); // environment effect
gotEffect = true;
continue;
}
stackPos++;
if(stackPos > 10)
g_logger.traceError(stdext::format("too many things, pos=%s, stackpos=%d", stdext::to_string(position), stackPos));
ThingPtr thing = getThing(msg);
g_map.addThing(thing, position, -2);
}
}
return 0;
}
Outfit ProtocolGame::getOutfit(const InputMessagePtr& msg)
{
Outfit outfit;
@@ -1376,6 +1385,31 @@ ThingPtr ProtocolGame::getThing(const InputMessagePtr& msg)
return thing;
}
ThingPtr ProtocolGame::getMappedThing(const InputMessagePtr& msg)
{
ThingPtr thing;
uint16 x = msg->getU16();
if(x != 0xffff) {
Position pos;
pos.x = x;
pos.y = msg->getU16();
pos.z = msg->getU8();
uint8 stackpos = msg->getU8();
assert(stackpos != 255);
thing = g_map.getThing(pos, stackpos);
if(!thing)
g_logger.traceError(stdext::format("no thing at pos:%s, stackpos:%d", stdext::to_string(pos), stackpos));
} else {
uint32 id = msg->getU32();
thing = g_map.getCreatureById(id);
if(!thing)
g_logger.traceError(stdext::format("no creature with id %u", id));
}
return thing;
}
CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
{
if(type == 0)
@@ -1397,7 +1431,7 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
uint id = msg->getU32();
int creatureType;
if(g_game.getProtocolVersion() >= 910)
if(g_game.getClientVersion() >= 910)
creatureType = msg->getU8();
else {
if(id >= Proto::PlayerStartId && id < Proto::PlayerEndId)
@@ -1416,8 +1450,13 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
if(id == m_localPlayer->getId())
creature = m_localPlayer;
else if(creatureType == Proto::CreatureTypePlayer)
creature = PlayerPtr(new Player);
else if(creatureType == Proto::CreatureTypePlayer) {
// fixes a bug server side bug where GameInit is not sent and local player id is unknown
if(m_localPlayer->getId() == 0 && name == m_localPlayer->getName())
creature = m_localPlayer;
else
creature = PlayerPtr(new Player);
}
else if(creatureType == Proto::CreatureTypeMonster)
creature = MonsterPtr(new Monster);
else if(creatureType == Proto::CreatureTypeNpc)
@@ -1447,13 +1486,13 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
// emblem is sent only when the creature is not known
int emblem = -1;
bool passable = false;
bool unpass = true;
if(g_game.getFeature(Otc::GameCreatureEmblems) && !known)
emblem = msg->getU8();
if(g_game.getProtocolVersion() >= 854)
passable = (msg->getU8() == 0);
if(g_game.getClientVersion() >= 854)
unpass = msg->getU8();
if(creature) {
creature->setHealthPercent(healthPercent);
@@ -1465,7 +1504,7 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
creature->setShield(shield);
if(emblem != -1)
creature->setEmblem(emblem);
creature->setPassable(passable);
creature->setPassable(!unpass);
if(creature == m_localPlayer && !m_localPlayer->isKnown())
m_localPlayer->setKnown(true);
@@ -1481,11 +1520,11 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
if(creature)
creature->turn(direction);
if(g_game.getProtocolVersion() >= 953) {
bool passable = msg->getU8();
if(g_game.getClientVersion() >= 953) {
bool unpass = msg->getU8();
if(creature)
creature->setPassable(passable);
creature->setPassable(!unpass);
}
} else {
@@ -1502,7 +1541,7 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
ItemPtr item = Item::create(id);
if(item->getId() == 0)
stdext::throw_exception("unable to create item with invalid id 0");
stdext::throw_exception(stdext::format("unable to create item with invalid id %d", id));
if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable())
item->setCountOrSubType(msg->getU8());
@@ -1511,7 +1550,7 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
if(item->getAnimationPhases() > 1) {
// 0xfe => random phase
// 0xff => async?
msg->getU8();
msg->getU8(); // phase
}
}

View File

@@ -51,7 +51,7 @@ void ProtocolGame::sendLoginPacket(uint challangeTimestamp, uint8 challangeRando
msg->addU8(Proto::ClientEnterGame);
msg->addU16(g_lua.callGlobalField<int>("g_game", "getOs"));
msg->addU16(g_game.getProtocolVersion());
msg->addU16(g_game.getClientVersion());
int paddingBytes = 128;
msg->addU8(0); // first RSA byte must be 0
@@ -509,21 +509,21 @@ void ProtocolGame::sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseMod
send(msg);
}
void ProtocolGame::sendAttack(uint creatureId)
void ProtocolGame::sendAttack(uint creatureId, uint seq)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientAttack);
msg->addU32(creatureId);
msg->addU32(0);
msg->addU32(0);
msg->addU32(seq);
send(msg);
}
void ProtocolGame::sendFollow(uint creatureId)
void ProtocolGame::sendFollow(uint creatureId, uint seq)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientFollow);
msg->addU32(creatureId);
msg->addU32(seq);
send(msg);
}
@@ -566,14 +566,14 @@ void ProtocolGame::sendLeaveParty()
send(msg);
}
void ProtocolGame::sendShareExperience(bool active, int unknown)
void ProtocolGame::sendShareExperience(bool active)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientShareExperience);
msg->addU8(active ? 0x01 : 0x00);
if(g_game.getProtocolVersion() < 910)
msg->addU8(unknown);
if(g_game.getClientVersion() < 910)
msg->addU8(0);
send(msg);
}

View File

@@ -34,18 +34,18 @@ SpriteManager::SpriteManager()
m_signature = 0;
}
void SpriteManager::termiante()
void SpriteManager::terminate()
{
unload();
}
bool SpriteManager::loadSpr(const std::string& file)
{
m_spritesCount = 0;
m_signature = 0;
m_loaded = false;
try {
m_spritesFile = g_resources.openFile(file);
if(!m_spritesFile)
return false;
// cache file buffer to avoid lags from hard drive
m_spritesFile->cache();

View File

@@ -32,7 +32,7 @@ class SpriteManager
public:
SpriteManager();
void termiante();
void terminate();
bool loadSpr(const std::string& file);
void unload();

View File

@@ -66,7 +66,7 @@ ContainerPtr Thing::getParentContainer()
int Thing::getStackpos()
{
if(m_position.x == 65535 && asItem()) // is inside a container
return 0;
return m_position.z;
else if(const TilePtr& tile = getTile())
return tile->getThingStackpos(asThing());
else {

View File

@@ -59,16 +59,17 @@ void ThingTypeManager::terminate()
bool ThingTypeManager::loadDat(const std::string& file)
{
m_datLoaded = false;
m_datSignature = 0;
try {
FileStreamPtr fin = g_resources.openFile(file);
if(!fin)
stdext::throw_exception("unable to open file");
m_datSignature = fin->getU32();
int numThings[ThingLastCategory];
for(int category = 0; category < ThingLastCategory; ++category) {
int count = fin->getU16() + 1;
m_thingTypes[category].clear();
m_thingTypes[category].resize(count, m_nullThingType);
}
@@ -114,9 +115,9 @@ void ThingTypeManager::loadOtb(const std::string& file)
m_itemTypes.resize(root->getChildren().size(), m_nullItemType);
for(const BinaryTreePtr& node : root->getChildren()) {
ItemTypePtr otbType(new ItemType);
otbType->unserialize(node);
addItemType(otbType);
ItemTypePtr itemType(new ItemType);
itemType->unserialize(node);
addItemType(itemType);
}
m_otbLoaded = true;
@@ -171,25 +172,25 @@ void ThingTypeManager::parseItemType(uint16 id, TiXmlElement* elem)
addItemType(newType);
}
ItemTypePtr otbType = getItemType(serverId);
otbType->setName(elem->Attribute("name"));
ItemTypePtr itemType = getItemType(serverId);
itemType->setName(elem->Attribute("name"));
for(TiXmlElement* attrib = elem->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
if(attrib->ValueStr() != "attribute")
break;
if(attrib->Attribute("key") == "description") {
otbType->setDesc(attrib->Attribute("value"));
itemType->setDesc(attrib->Attribute("value"));
break;
}
}
}
void ThingTypeManager::addItemType(const ItemTypePtr& otbType)
void ThingTypeManager::addItemType(const ItemTypePtr& itemType)
{
uint16 id = otbType->getServerId();
uint16 id = itemType->getServerId();
if(m_itemTypes.size() <= id)
m_itemTypes.resize(id+1, m_nullItemType);
m_itemTypes[id] = otbType;
m_itemTypes[id] = itemType;
}
const ItemTypePtr& ThingTypeManager::findOtbForClientId(uint16 id)
@@ -197,9 +198,9 @@ const ItemTypePtr& ThingTypeManager::findOtbForClientId(uint16 id)
if(m_itemTypes.empty())
return m_nullItemType;
for(const ItemTypePtr& otbType : m_itemTypes) {
if(otbType->getClientId() == id)
return otbType;
for(const ItemTypePtr& itemType : m_itemTypes) {
if(itemType->getClientId() == id)
return itemType;
}
return m_nullItemType;

View File

@@ -40,7 +40,7 @@ public:
void loadXml(const std::string& file);
void parseItemType(uint16 id, TiXmlElement *elem);
void addItemType(const ItemTypePtr& otbType);
void addItemType(const ItemTypePtr& itemType);
const ItemTypePtr& findOtbForClientId(uint16 id);
const ThingTypePtr& getNullThingType() { return m_nullThingType; }

View File

@@ -392,7 +392,7 @@ bool Tile::isWalkable()
return false;
if(CreaturePtr creature = thing->asCreature()) {
if(!creature->getPassable())
if(!creature->isPassable())
return false;
}
}
@@ -405,7 +405,7 @@ bool Tile::isPathable()
return false;
for(const ThingPtr& thing : m_things) {
if(thing->isNotPathable())
if(thing->isNotPathable() || thing->isCreature())
return false;
}
@@ -507,4 +507,13 @@ void Tile::update()
if(c != 0)
m_minimapColorByte = c;
}
// check stack priorities
// this code exists to find stackpos bugs faster
int lastPriority = 0;
for(const ThingPtr& thing : m_things) {
int priority = thing->getStackPriority();
assert(lastPriority <= priority);
lastPriority = priority;
}
}