You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2439 lines
86 KiB

#include <thread>
#include "Server.h"
namespace DAPI {
Server::Server()
: FPS(20)
{
output.open("output.csv");
data = std::make_unique<GameData>();
for (int x = -8; x < 9; x++) {
switch (x) {
case 8:
panelScreenCheck[std::make_pair(x, 3)] = true;
break;
case 7:
for (int y = 2; y < 5; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case 6:
for (int y = 1; y < 6; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case 5:
for (int y = 0; y < 7; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case 4:
for (int y = -1; y < 8; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case 3:
for (int y = -2; y < 9; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case 2:
for (int y = -3; y < 8; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case 1:
for (int y = -4; y < 7; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case 0:
for (int y = -5; y < 6; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case -1:
for (int y = -6; y < 5; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case -2:
for (int y = -7; y < 4; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case -3:
for (int y = -8; y < 3; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case -4:
for (int y = -7; y < 2; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case -5:
for (int y = -6; y < 1; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case -6:
for (int y = -5; y < 0; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case -7:
for (int y = -4; y < -1; y++)
panelScreenCheck[std::make_pair(x, y)] = true;
break;
case -8:
panelScreenCheck[std::make_pair(x, -3)] = true;
break;
}
}
}
void Server::update()
{
if (isConnected()) {
updateGameData();
protoClient.transmitMessages();
protoClient.receiveMessages();
processMessages();
} else {
checkForConnections();
}
}
bool Server::isConnected() const
{
return protoClient.isConnected();
}
void Server::processMessages()
{
bool issuedCommand = false;
while (protoClient.messageQueueSize()) {
auto message = protoClient.getNextMessage();
if (message.get() == nullptr)
return;
if (message->has_endofqueue())
return;
if (message->has_command() && !issuedCommand) {
auto command = message->command();
if (command.has_move() && this->OKToAct()) {
auto moveMessage = command.move();
this->move(moveMessage.targetx(), moveMessage.targety());
} else if (command.has_talk() && this->OKToAct()) {
auto talkMessage = command.talk();
this->talk(talkMessage.targetx(), talkMessage.targety());
} else if (command.has_option() && this->data->stextflag) {
auto option = command.option();
this->selectStoreOption(static_cast<StoreOption>(command.option().option()));
} else if (command.has_buyitem()) {
auto buyItem = command.buyitem();
this->buyItem(buyItem.id());
} else if (command.has_sellitem()) {
auto sellItem = command.sellitem();
this->sellItem(sellItem.id());
} else if (command.has_rechargeitem()) {
auto rechargeItem = command.rechargeitem();
this->rechargeItem(rechargeItem.id());
} else if (command.has_repairitem()) {
auto repairItem = command.repairitem();
this->repairItem(repairItem.id());
} else if (command.has_attackmonster()) {
auto attackMonster = command.attackmonster();
this->attackMonster(attackMonster.index());
} else if (command.has_attackxy()) {
auto attackXY = command.attackxy();
this->attackXY(attackXY.x(), attackXY.y());
} else if (command.has_operateobject()) {
auto operateObject = command.operateobject();
this->operateObject(operateObject.index());
} else if (command.has_usebeltitem()) {
auto useBeltItem = command.usebeltitem();
this->useBeltItem(useBeltItem.slot());
} else if (command.has_togglecharactersheet()) {
auto toggleCharacterSheet = command.togglecharactersheet();
this->toggleCharacterScreen();
} else if (command.has_increasestat()) {
auto increaseStat = command.increasestat();
this->increaseStat(static_cast<CommandType>(increaseStat.stat()));
} else if (command.has_getitem()) {
auto getItem = command.getitem();
this->getItem(getItem.id());
} else if (command.has_setspell()) {
auto setSpell = command.setspell();
this->setSpell(setSpell.spellid(), static_cast<devilution::SpellType>(setSpell.spelltype()));
} else if (command.has_castmonster()) {
auto castMonster = command.castmonster();
this->castSpell(castMonster.index());
} else if (command.has_toggleinventory()) {
this->toggleInventory();
} else if (command.has_putincursor()) {
auto putInCursor = command.putincursor();
this->putInCursor(putInCursor.id());
} else if (command.has_putcursoritem()) {
auto putCursorItem = command.putcursoritem();
this->putCursorItem(putCursorItem.target());
} else if (command.has_dropcursoritem()) {
this->dropCursorItem();
} else if (command.has_useitem()) {
auto useItem = command.useitem();
this->useItem(useItem.id());
} else if (command.has_identifystoreitem()) {
auto identifyStoreItem = command.identifystoreitem();
this->identifyStoreItem(identifyStoreItem.id());
} else if (command.has_castxy()) {
auto castXY = command.castxy();
this->castSpell(castXY.x(), castXY.y());
} else if (command.has_cancelqtext()) {
this->cancelQText();
} else if (command.has_disarmtrap()) {
auto disarmTrap = command.disarmtrap();
this->disarmTrap(disarmTrap.index());
} else if (command.has_skillrepair()) {
auto skillRepair = command.skillrepair();
this->skillRepair(skillRepair.id());
} else if (command.has_skillrecharge()) {
auto skillRecharge = command.skillrecharge();
this->skillRecharge(skillRecharge.id());
} else if (command.has_togglemenu()) {
this->toggleMenu();
} else if (command.has_savegame()) {
this->saveGame();
} else if (command.has_quit()) {
this->quit();
} else if (command.has_clearcursor()) {
this->clearCursor();
} else if (command.has_identifyitem()) {
auto identifyItem = command.identifyitem();
this->identifyItem(identifyItem.id());
}
issuedCommand = true;
if (command.has_setfps()) {
auto setfps = command.setfps();
this->setFPS(setfps.fps());
issuedCommand = false;
}
}
}
}
void Server::checkForConnections()
{
if (isConnected())
return;
if (!listening) {
protoClient.initListen();
listening = false;
}
protoClient.checkForConnection();
if (!protoClient.isConnected())
return;
protoClient.stopListen();
}
void Server::updateGameData()
{
std::vector<int> itemsModified;
auto fullFillItemInfo = [&](int itemID, devilution::Item *item) {
itemsModified.push_back(itemID);
data->itemList[itemID].ID = itemID;
data->itemList[itemID]._iSeed = item->_iSeed;
data->itemList[itemID]._iCreateInfo = item->_iCreateInfo;
data->itemList[itemID]._itype = static_cast<int>(item->_itype);
data->itemList[itemID]._ix = item->position.x;
data->itemList[itemID]._iy = item->position.y;
data->itemList[itemID]._iIdentified = item->_iIdentified;
data->itemList[itemID]._iMagical = item->_iMagical;
strcpy(data->itemList[itemID]._iName, item->_iName);
if (data->itemList[itemID]._iIdentified) {
strcpy(data->itemList[itemID]._iIName, item->_iIName);
data->itemList[itemID]._iFlags = static_cast<int>(item->_iFlags);
data->itemList[itemID]._iPrePower = item->_iPrePower;
data->itemList[itemID]._iSufPower = item->_iSufPower;
data->itemList[itemID]._iPLDam = item->_iPLDam;
data->itemList[itemID]._iPLToHit = item->_iPLToHit;
data->itemList[itemID]._iPLAC = item->_iPLAC;
data->itemList[itemID]._iPLStr = item->_iPLStr;
data->itemList[itemID]._iPLMag = item->_iPLMag;
data->itemList[itemID]._iPLDex = item->_iPLDex;
data->itemList[itemID]._iPLVit = item->_iPLVit;
data->itemList[itemID]._iPLFR = item->_iPLFR;
data->itemList[itemID]._iPLLR = item->_iPLLR;
data->itemList[itemID]._iPLMR = item->_iPLMR;
data->itemList[itemID]._iPLMana = item->_iPLMana;
data->itemList[itemID]._iPLHP = item->_iPLHP;
data->itemList[itemID]._iPLDamMod = item->_iPLDamMod;
data->itemList[itemID]._iPLGetHit = item->_iPLGetHit;
data->itemList[itemID]._iPLLight = item->_iPLLight;
data->itemList[itemID]._iSplLvlAdd = item->_iSplLvlAdd;
data->itemList[itemID]._iFMinDam = item->_iFMinDam;
data->itemList[itemID]._iFMaxDam = item->_iFMaxDam;
data->itemList[itemID]._iLMinDam = item->_iLMinDam;
data->itemList[itemID]._iLMaxDam = item->_iLMaxDam;
} else {
strcpy(data->itemList[itemID]._iName, item->_iName);
data->itemList[itemID]._iFlags = -1;
data->itemList[itemID]._iPrePower = -1;
data->itemList[itemID]._iSufPower = -1;
data->itemList[itemID]._iPLDam = -1;
data->itemList[itemID]._iPLToHit = -1;
data->itemList[itemID]._iPLAC = -1;
data->itemList[itemID]._iPLStr = -1;
data->itemList[itemID]._iPLMag = -1;
data->itemList[itemID]._iPLDex = -1;
data->itemList[itemID]._iPLVit = -1;
data->itemList[itemID]._iPLFR = -1;
data->itemList[itemID]._iPLLR = -1;
data->itemList[itemID]._iPLMR = -1;
data->itemList[itemID]._iPLMana = -1;
data->itemList[itemID]._iPLHP = -1;
data->itemList[itemID]._iPLDamMod = -1;
data->itemList[itemID]._iPLGetHit = -1;
data->itemList[itemID]._iPLLight = -1;
data->itemList[itemID]._iSplLvlAdd = -1;
data->itemList[itemID]._iFMinDam = -1;
data->itemList[itemID]._iFMaxDam = -1;
data->itemList[itemID]._iLMinDam = -1;
data->itemList[itemID]._iLMaxDam = -1;
}
data->itemList[itemID]._iClass = item->_iClass;
data->itemList[itemID]._iCurs = item->_iCurs;
if (item->_itype == devilution::ItemType::Gold)
data->itemList[itemID]._ivalue = item->_ivalue;
else
data->itemList[itemID]._ivalue = -1;
data->itemList[itemID]._iMinDam = item->_iMinDam;
data->itemList[itemID]._iMaxDam = item->_iMaxDam;
data->itemList[itemID]._iAC = item->_iAC;
data->itemList[itemID]._iMiscId = item->_iMiscId;
data->itemList[itemID]._iSpell = static_cast<int>(item->_iSpell);
data->itemList[itemID]._iCharges = item->_iCharges;
data->itemList[itemID]._iMaxCharges = item->_iMaxCharges;
data->itemList[itemID]._iDurability = item->_iDurability;
data->itemList[itemID]._iMaxDur = item->_iMaxDur;
data->itemList[itemID]._iMinStr = item->_iMinStr;
data->itemList[itemID]._iMinMag = item->_iMinMag;
data->itemList[itemID]._iMinDex = item->_iMinDex;
data->itemList[itemID]._iStatFlag = item->_iStatFlag;
data->itemList[itemID].IDidx = item->IDidx;
};
auto partialFillItemInfo = [&](int itemID, devilution::Item *item) {
itemsModified.push_back(itemID);
data->itemList[itemID].ID = itemID;
data->itemList[itemID]._iSeed = item->_iSeed;
data->itemList[itemID]._iCreateInfo = item->_iCreateInfo;
data->itemList[itemID]._itype = static_cast<int>(item->_itype);
data->itemList[itemID]._ix = item->position.x;
data->itemList[itemID]._iy = item->position.y;
data->itemList[itemID]._iIdentified = item->_iIdentified;
data->itemList[itemID]._iMagical = item->_iMagical;
strcpy(data->itemList[itemID]._iName, item->_iName);
if (data->itemList[itemID]._iIdentified)
strcpy(data->itemList[itemID]._iIName, item->_iIName);
else
strcpy(data->itemList[itemID]._iName, item->_iName);
data->itemList[itemID]._iFlags = -1;
data->itemList[itemID]._iPrePower = -1;
data->itemList[itemID]._iSufPower = -1;
data->itemList[itemID]._iPLDam = -1;
data->itemList[itemID]._iPLToHit = -1;
data->itemList[itemID]._iPLAC = -1;
data->itemList[itemID]._iPLStr = -1;
data->itemList[itemID]._iPLMag = -1;
data->itemList[itemID]._iPLDex = -1;
data->itemList[itemID]._iPLVit = -1;
data->itemList[itemID]._iPLFR = -1;
data->itemList[itemID]._iPLLR = -1;
data->itemList[itemID]._iPLMR = -1;
data->itemList[itemID]._iPLMana = -1;
data->itemList[itemID]._iPLHP = -1;
data->itemList[itemID]._iPLDamMod = -1;
data->itemList[itemID]._iPLGetHit = -1;
data->itemList[itemID]._iPLLight = -1;
data->itemList[itemID]._iSplLvlAdd = -1;
data->itemList[itemID]._iFMinDam = -1;
data->itemList[itemID]._iFMaxDam = -1;
data->itemList[itemID]._iLMinDam = -1;
data->itemList[itemID]._iLMaxDam = -1;
data->itemList[itemID]._iClass = item->_iClass;
data->itemList[itemID]._iCurs = item->_iCurs;
if (item->_itype == devilution::ItemType::Gold)
data->itemList[itemID]._ivalue = item->_ivalue;
else
data->itemList[itemID]._ivalue = -1;
data->itemList[itemID]._iMinDam = -1;
data->itemList[itemID]._iMaxDam = -1;
data->itemList[itemID]._iAC = -1;
data->itemList[itemID]._iMiscId = item->_iMiscId;
data->itemList[itemID]._iSpell = static_cast<int>(item->_iSpell);
data->itemList[itemID]._iCharges = -1;
data->itemList[itemID]._iMaxCharges = -1;
data->itemList[itemID]._iDurability = -1;
data->itemList[itemID]._iMaxDur = -1;
data->itemList[itemID]._iMinStr = -1;
data->itemList[itemID]._iMinMag = -1;
data->itemList[itemID]._iMinDex = -1;
data->itemList[itemID]._iStatFlag = -1;
data->itemList[itemID].IDidx = item->IDidx;
};
auto isOnScreen = [&](int x, int y) {
int dx = devilution::Players[devilution::MyPlayerId].position.tile.x - x;
int dy = devilution::Players[devilution::MyPlayerId].position.tile.y - y;
if (!devilution::CharFlag && !devilution::invflag) {
if (dy > 0) {
if (dx < 1 && abs(dx) + abs(dy) < 11) {
return true;
} else if (dx > 0 && abs(dx) + abs(dy) < 12) {
return true;
}
} else {
if ((dx > -1 || dy == 0) && abs(dx) + abs(dy) < 11) {
return true;
} else if ((dx < 0 && dy != 0) && abs(dx) + abs(dy) < 12) {
return true;
}
}
} else if ((devilution::CharFlag && !devilution::invflag) || (!devilution::CharFlag && devilution::invflag)) {
return panelScreenCheck[std::make_pair(dx, dy)];
}
return false;
};
auto message = std::make_unique<dapi::message::Message>();
auto update = message->mutable_frameupdate();
data->player = devilution::MyPlayerId;
update->set_player(data->player);
data->stextflag = static_cast<char>(devilution::ActiveStore);
update->set_stextflag(data->stextflag);
data->pauseMode = devilution::PauseMode;
update->set_pausemode(data->pauseMode);
if (devilution::sgpCurrentMenu != nullptr)
data->menuOpen = true;
else
data->menuOpen = false;
update->set_menuopen(data->menuOpen);
data->pcurs = devilution::pcurs;
update->set_cursor(devilution::pcurs);
data->chrflag = devilution::CharFlag;
update->set_chrflag(devilution::CharFlag);
data->invflag = devilution::invflag;
update->set_invflag(devilution::invflag);
data->qtextflag = devilution::qtextflag;
update->set_qtextflag(devilution::qtextflag);
if (!devilution::setlevel)
data->currlevel = static_cast<int>(devilution::currlevel);
else
data->currlevel = static_cast<int>(devilution::setlvlnum);
update->set_currlevel(data->currlevel);
data->setlevel = static_cast<bool>(devilution::setlevel);
update->set_setlevel(devilution::setlevel);
if (devilution::qtextflag) {
std::stringstream qtextss;
for (auto &line : devilution::TextLines)
qtextss << line;
update->set_qtext(qtextss.str().c_str());
}
else
update->set_qtext("");
update->set_fps(FPS);
if (!devilution::gbIsMultiplayer)
update->set_gamemode(0);
else
update->set_gamemode(1);
update->set_gndifficulty(devilution::sgGameInitInfo.nDifficulty);
int range = 10;
if (devilution::MyPlayer->isWalking()) {
range = 11;
}
for (int x = 0; x < 112; x++) {
for (int y = 0; y < 112; y++) {
if (isOnScreen(x, y)) {
auto dpiece = update->add_dpiece();
dpiece->set_type(devilution::dPiece[x][y]);
dpiece->set_solid(HasAnyOf(devilution::SOLData[dpiece->type()], devilution::TileProperties::Solid));
dpiece->set_x(x);
dpiece->set_y(y);
dpiece->set_stopmissile(HasAnyOf(devilution::SOLData[dpiece->type()], devilution::TileProperties::BlockMissile));
}
}
}
for (int i = 0; i < devilution::numtrigs; i++) {
if (isOnScreen(devilution::trigs[i].position.x, devilution::trigs[i].position.y)) {
auto trigger = update->add_triggerdata();
trigger->set_lvl(devilution::trigs[i]._tlvl);
trigger->set_x(devilution::trigs[i].position.x);
trigger->set_y(devilution::trigs[i].position.y);
trigger->set_type(devilution::trigs[i]._tmsg);
}
}
for (int i = 0; i < MAXQUESTS; i++) {
auto quest = update->add_questdata();
quest->set_id(i);
if (devilution::Quests[i]._qactive == 2)
quest->set_state(devilution::Quests[i]._qactive);
else
quest->set_state(0);
if (devilution::currlevel == devilution::Quests[i]._qlevel && devilution::Quests[i]._qslvl != 0 && devilution::Quests[i]._qactive != devilution::quest_state::QUEST_NOTAVAIL) {
auto trigger = update->add_triggerdata();
trigger->set_lvl(devilution::Quests[i]._qslvl);
trigger->set_x(devilution::Quests[i].position.x);
trigger->set_y(devilution::Quests[i].position.y);
trigger->set_type(1029);
}
}
data->storeList.clear();
if (devilution::ActiveStore != devilution::TalkID::None) {
for (int i = 0; i < 24; i++) {
if (devilution::TextLine[i].isSelectable()) {
if (!strcmp(devilution::TextLine[i].text.c_str(), "Talk to Cain") || !strcmp(devilution::TextLine[i].text.c_str(), "Talk to Farnham") || !strcmp(devilution::TextLine[i].text.c_str(), "Talk to Pepin") || !strcmp(devilution::TextLine[i].text.c_str(), "Talk to Gillian") || !strcmp(devilution::TextLine[i].text.c_str(), "Talk to Ogden") || !strcmp(devilution::TextLine[i].text.c_str(), "Talk to Griswold") || !strcmp(devilution::TextLine[i].text.c_str(), "Talk to Adria") || !strcmp(devilution::TextLine[i].text.c_str(), "Talk to Wirt"))
data->storeList.push_back(StoreOption::TALK);
else if (!strcmp(devilution::TextLine[i].text.c_str(), "Identify an item"))
data->storeList.push_back(StoreOption::IDENTIFYANITEM);
else if (!strcmp(devilution::TextLine[i].text.c_str(), "Say goodbye") || !strcmp(devilution::TextLine[i].text.c_str(), "Say Goodbye") || !strcmp(devilution::TextLine[i].text.c_str(), "Leave Healer's home") || !strcmp(devilution::TextLine[i].text.c_str(), "Leave the shop") || !strcmp(devilution::TextLine[i].text.c_str(), "Leave the shack") || !strcmp(devilution::TextLine[i].text.c_str(), "Leave the tavern") || !strcmp(devilution::TextLine[i].text.c_str(), "Leave"))
data->storeList.push_back(StoreOption::EXIT);
else if (!strcmp(devilution::TextLine[i].text.c_str(), "Receive healing"))
data->storeList.push_back(StoreOption::HEAL);
else if (!strcmp(devilution::TextLine[i].text.c_str(), "Buy items"))
data->storeList.push_back(StoreOption::BUYITEMS);
else if (!strcmp(devilution::TextLine[i].text.c_str(), "What have you got?"))
data->storeList.push_back(StoreOption::WIRTPEEK);
else if (!strcmp(devilution::TextLine[i].text.c_str(), "Buy basic items"))
data->storeList.push_back(StoreOption::BUYBASIC);
else if (!strcmp(devilution::TextLine[i].text.c_str(), "Buy premium items"))
data->storeList.push_back(StoreOption::BUYPREMIUM);
else if (!strcmp(devilution::TextLine[i].text.c_str(), "Sell items"))
data->storeList.push_back(StoreOption::SELL);
else if (!strcmp(devilution::TextLine[i].text.c_str(), "Repair items"))
data->storeList.push_back(StoreOption::REPAIR);
else if (!strcmp(devilution::TextLine[i].text.c_str(), "Recharge staves"))
data->storeList.push_back(StoreOption::RECHARGE);
}
}
switch (devilution::ActiveStore) {
case devilution::TalkID::HealerBuy:
case devilution::TalkID::StorytellerIdentifyShow:
case devilution::TalkID::NoMoney:
case devilution::TalkID::NoRoom:
case devilution::TalkID::SmithBuy:
case devilution::TalkID::StorytellerIdentify:
case devilution::TalkID::SmithPremiumBuy:
case devilution::TalkID::SmithRepair:
case devilution::TalkID::SmithSell:
case devilution::TalkID::WitchBuy:
case devilution::TalkID::WitchRecharge:
case devilution::TalkID::WitchSell:
case devilution::TalkID::Gossip:
data->storeList.push_back(StoreOption::BACK);
break;
default:
break;
}
}
for (auto &option : data->storeList)
update->add_storeoption(static_cast<int>(option));
data->groundItems.clear();
for (int i = 0; i < 4; i++) {
auto playerData = update->add_playerdata();
data->playerList[i].InvBody.clear();
data->playerList[i].pnum = i;
playerData->set_pnum(i);
memcpy(data->playerList[i]._pName, devilution::Players[i]._pName, 32);
playerData->set__pname(data->playerList[i]._pName);
for (int j = 0; j < MAXINV; j++)
data->playerList[i].InvList[j] = -1;
if (devilution::MyPlayerId == i) {
data->playerList[i]._pmode = devilution::Players[i]._pmode;
data->playerList[i].plrlevel = devilution::Players[i].plrlevel;
data->playerList[i]._px = devilution::Players[i].position.tile.x;
data->playerList[i]._py = devilution::Players[i].position.tile.y;
data->playerList[i]._pfutx = devilution::Players[i].position.future.x;
data->playerList[i]._pfuty = devilution::Players[i].position.future.y;
data->playerList[i]._pdir = static_cast<int>(devilution::Players[i]._pdir);
data->playerList[i]._pRSpell = static_cast<int>(devilution::Players[i]._pRSpell);
data->playerList[i]._pRSplType = static_cast<char>(devilution::Players[i]._pRSplType);
memcpy(data->playerList[i]._pSplLvl, devilution::Players[i]._pSplLvl, sizeof(data->playerList[i]._pSplLvl));
data->playerList[i]._pMemSpells = devilution::Players[i]._pMemSpells;
data->playerList[i]._pAblSpells = devilution::Players[i]._pAblSpells;
data->playerList[i]._pScrlSpells = devilution::Players[i]._pScrlSpells;
data->playerList[i]._pClass = static_cast<char>(devilution::Players[i]._pClass);
data->playerList[i]._pStrength = devilution::Players[i]._pStrength;
data->playerList[i]._pBaseStr = devilution::Players[i]._pBaseStr;
data->playerList[i]._pMagic = devilution::Players[i]._pMagic;
data->playerList[i]._pBaseMag = devilution::Players[i]._pBaseMag;
data->playerList[i]._pDexterity = devilution::Players[i]._pDexterity;
data->playerList[i]._pBaseDex = devilution::Players[i]._pBaseDex;
data->playerList[i]._pVitality = devilution::Players[i]._pVitality;
data->playerList[i]._pBaseVit = devilution::Players[i]._pBaseVit;
data->playerList[i]._pStatPts = devilution::Players[i]._pStatPts;
data->playerList[i]._pDamageMod = devilution::Players[i]._pDamageMod;
data->playerList[i]._pHitPoints = devilution::Players[i]._pHitPoints;
data->playerList[i]._pMaxHP = devilution::Players[i]._pMaxHP;
data->playerList[i]._pMana = devilution::Players[i]._pMana;
data->playerList[i]._pMaxMana = devilution::Players[i]._pMaxMana;
data->playerList[i]._pLevel = devilution::Players[i].getCharacterLevel();
data->playerList[i]._pExperience = devilution::Players[i]._pExperience;
data->playerList[i]._pArmorClass = devilution::Players[i]._pArmorClass;
data->playerList[i]._pMagResist = devilution::Players[i]._pMagResist;
data->playerList[i]._pFireResist = devilution::Players[i]._pFireResist;
data->playerList[i]._pLightResist = devilution::Players[i]._pLghtResist;
data->playerList[i]._pGold = devilution::Players[i]._pGold;
for (int j = 0; j < NUM_INVLOC; j++) {
if (devilution::Players[i].InvBody[j]._itype == devilution::ItemType::None) {
data->playerList[i].InvBody[j] = -1;
continue;
}
int itemID = static_cast<int>(data->itemList.size());
for (int k = 0; k < data->itemList.size(); k++) {
if (data->itemList[k].compare(devilution::Players[i].InvBody[j])) {
itemID = k;
break;
}
}
if (itemID == data->itemList.size())
data->itemList.push_back(ItemData {});
fullFillItemInfo(itemID, &devilution::Players[i].InvBody[j]);
data->playerList[i].InvBody[j] = itemID;
}
bool used[40] = { false };
for (int j = 0; j < MAXINV; j++) {
auto index = devilution::Players[i].InvGrid[j];
if (index != 0) {
int itemID = static_cast<int>(data->itemList.size());
for (int k = 0; k < data->itemList.size(); k++) {
if (data->itemList[k].compare(devilution::Players[i].InvList[abs(index) - 1])) {
itemID = k;
break;
}
}
data->playerList[i].InvGrid[j] = itemID;
if (!used[abs(index) - 1]) {
if (itemID == data->itemList.size())
data->itemList.push_back(ItemData {});
fullFillItemInfo(itemID, &devilution::Players[i].InvList[abs(index) - 1]);
used[abs(index) - 1] = true;
data->playerList[i].InvList[abs(index) - 1] = itemID;
}
} else
data->playerList[i].InvGrid[j] = -1;
}
for (int j = 0; j < MAXSPD; j++) {
if (devilution::Players[i].SpdList[j]._itype == devilution::ItemType::None) {
data->playerList[i].SpdList[j] = -1;
continue;
}
int itemID = static_cast<int>(data->itemList.size());
for (int k = 0; k < data->itemList.size(); k++) {
if (data->itemList[k].compare(devilution::Players[i].SpdList[j])) {
itemID = k;
break;
}
}
if (itemID == data->itemList.size())
data->itemList.push_back(ItemData {});
fullFillItemInfo(itemID, &devilution::Players[i].SpdList[j]);
data->playerList[i].SpdList[j] = itemID;
}
if (devilution::pcurs < 12)
data->playerList[i].HoldItem = -1;
else {
int itemID = static_cast<int>(data->itemList.size());
for (int j = 0; j < data->itemList.size(); j++) {
if (data->itemList[j].compare(devilution::Players[i].HoldItem)) {
itemID = j;
break;
}
}
if (itemID == data->itemList.size())
data->itemList.push_back(ItemData {});
partialFillItemInfo(itemID, &devilution::Players[i].HoldItem);
data->playerList[i].HoldItem = itemID;
}
data->playerList[i]._pIMinDam = devilution::Players[i]._pIMinDam;
data->playerList[i]._pIMaxDam = devilution::Players[i]._pIMaxDam;
data->playerList[i]._pIBonusDam = devilution::Players[i]._pIBonusDam;
data->playerList[i]._pIAC = devilution::Players[i]._pIAC;
data->playerList[i]._pIBonusToHit = devilution::Players[i]._pIBonusToHit;
data->playerList[i]._pIBonusAC = devilution::Players[i]._pIBonusAC;
data->playerList[i]._pIBonusDamMod = devilution::Players[i]._pIBonusDamMod;
data->playerList[i].pManaShield = devilution::Players[i].pManaShield;
} else if (devilution::IsTileLit(devilution::Point { devilution::Players[i].position.tile.x, devilution::Players[i].position.tile.y })) {
data->playerList[i]._pmode = devilution::Players[i]._pmode;
data->playerList[i].plrlevel = devilution::Players[i].plrlevel;
data->playerList[i]._px = devilution::Players[i].position.tile.x;
data->playerList[i]._py = devilution::Players[i].position.tile.y;
data->playerList[i]._pfutx = devilution::Players[i].position.future.x;
data->playerList[i]._pfuty = devilution::Players[i].position.future.y;
data->playerList[i]._pdir = static_cast<int>(devilution::Players[i]._pdir);
data->playerList[i]._pRSpell = -1;
data->playerList[i]._pRSplType = 4;
memset(data->playerList[i]._pSplLvl, 0, 64);
data->playerList[i]._pMemSpells = -1;
data->playerList[i]._pAblSpells = -1;
data->playerList[i]._pScrlSpells = -1;
data->playerList[i]._pClass = static_cast<char>(devilution::Players[i]._pClass);
data->playerList[i]._pStrength = -1;
data->playerList[i]._pBaseStr = -1;
data->playerList[i]._pMagic = -1;
data->playerList[i]._pBaseMag = -1;
data->playerList[i]._pDexterity = -1;
data->playerList[i]._pBaseDex = -1;
data->playerList[i]._pVitality = -1;
data->playerList[i]._pBaseVit = -1;
data->playerList[i]._pStatPts = -1;
data->playerList[i]._pDamageMod = -1;
data->playerList[i]._pHitPoints = devilution::Players[i]._pHitPoints;
data->playerList[i]._pMaxHP = devilution::Players[i]._pMaxHP;
data->playerList[i]._pMana = -1;
data->playerList[i]._pMaxMana = -1;
data->playerList[i]._pLevel = devilution::Players[i].getCharacterLevel();
data->playerList[i]._pExperience = -1;
data->playerList[i]._pArmorClass = -1;
data->playerList[i]._pMagResist = -1;
data->playerList[i]._pFireResist = -1;
data->playerList[i]._pLightResist = -1;
data->playerList[i]._pGold = -1;
for (int j = 0; j < NUM_INVLOC; j++)
data->playerList[i].InvBody[j] = -1;
for (int j = 0; j < MAXINV; j++)
data->playerList[i].InvGrid[j] = -1;
for (int j = 0; j < MAXSPD; j++)
data->playerList[i].SpdList[j] = -1;
data->playerList[i].HoldItem = -1;
data->playerList[i]._pIMinDam = -1;
data->playerList[i]._pIMaxDam = -1;
data->playerList[i]._pIBonusDam = -1;
data->playerList[i]._pIAC = -1;
data->playerList[i]._pIBonusToHit = -1;
data->playerList[i]._pIBonusAC = -1;
data->playerList[i]._pIBonusDamMod = -1;
data->playerList[i].pManaShield = devilution::Players[i].pManaShield;
} else {
data->playerList[i]._pmode = 0;
data->playerList[i].plrlevel = -1;
data->playerList[i]._px = -1;
data->playerList[i]._py = -1;
data->playerList[i]._pfutx = -1;
data->playerList[i]._pfuty = -1;
data->playerList[i]._pdir = -1;
data->playerList[i]._pRSpell = -1;
data->playerList[i]._pRSplType = -1;
memset(data->playerList[i]._pSplLvl, 0, 64);
data->playerList[i]._pMemSpells = -1;
data->playerList[i]._pAblSpells = -1;
data->playerList[i]._pScrlSpells = -1;
data->playerList[i]._pClass = -1;
data->playerList[i]._pStrength = -1;
data->playerList[i]._pBaseStr = -1;
data->playerList[i]._pMagic = -1;
data->playerList[i]._pBaseMag = -1;
data->playerList[i]._pDexterity = -1;
data->playerList[i]._pBaseDex = -1;
data->playerList[i]._pVitality = -1;
data->playerList[i]._pBaseVit = -1;
data->playerList[i]._pStatPts = -1;
data->playerList[i]._pDamageMod = -1;
data->playerList[i]._pHitPoints = -1;
data->playerList[i]._pMaxHP = -1;
data->playerList[i]._pMana = -1;
data->playerList[i]._pMaxMana = -1;
data->playerList[i]._pLevel = devilution::Players[i].getCharacterLevel();
data->playerList[i]._pExperience = -1;
data->playerList[i]._pArmorClass = -1;
data->playerList[i]._pMagResist = -1;
data->playerList[i]._pFireResist = -1;
data->playerList[i]._pLightResist = -1;
data->playerList[i]._pIBonusToHit = -1;
data->playerList[i]._pGold = -1;
for (int j = 0; j < NUM_INVLOC; j++)
data->playerList[i].InvBody[j] = -1;
for (int j = 0; j < MAXINV; j++)
data->playerList[i].InvGrid[j] = -1;
for (int j = 0; j < MAXSPD; j++)
data->playerList[i].SpdList[j] = -1;
data->playerList[i].HoldItem = -1;
data->playerList[i]._pIMinDam = -1;
data->playerList[i]._pIMaxDam = -1;
data->playerList[i]._pIBonusDam = -1;
data->playerList[i]._pIAC = -1;
data->playerList[i]._pIBonusToHit = -1;
data->playerList[i]._pIBonusAC = -1;
data->playerList[i]._pIBonusDamMod = -1;
data->playerList[i].pManaShield = false;
}
playerData->set__pmode(data->playerList[i]._pmode);
playerData->set_plrlevel(data->playerList[i].plrlevel);
playerData->set__px(data->playerList[i]._px);
playerData->set__py(data->playerList[i]._py);
playerData->set__pfutx(data->playerList[i]._pfutx);
playerData->set__pfuty(data->playerList[i]._pfuty);
playerData->set__pdir(data->playerList[i]._pdir);
playerData->set__prspell(data->playerList[i]._pRSpell);
playerData->set__prspltype(data->playerList[i]._pRSplType);
for (int j = 0; j < 64; j++)
playerData->add__pspllvl(data->playerList[i]._pSplLvl[j]);
playerData->set__pmemspells(data->playerList[i]._pMemSpells);
playerData->set__pablspells(data->playerList[i]._pAblSpells);
playerData->set__pscrlspells(data->playerList[i]._pScrlSpells);
playerData->set__pclass(data->playerList[i]._pClass);
playerData->set__pstrength(data->playerList[i]._pStrength);
playerData->set__pbasestr(data->playerList[i]._pBaseStr);
playerData->set__pmagic(data->playerList[i]._pMagic);
playerData->set__pbasemag(data->playerList[i]._pBaseMag);
playerData->set__pdexterity(data->playerList[i]._pDexterity);
playerData->set__pbasedex(data->playerList[i]._pBaseDex);
playerData->set__pvitality(data->playerList[i]._pVitality);
playerData->set__pbasevit(data->playerList[i]._pBaseVit);
playerData->set__pstatpts(data->playerList[i]._pStatPts);
playerData->set__pdamagemod(data->playerList[i]._pDamageMod);
playerData->set__phitpoints(data->playerList[i]._pHitPoints);
playerData->set__pmaxhp(data->playerList[i]._pMaxHP);
playerData->set__pmana(data->playerList[i]._pMana);
playerData->set__pmaxmana(data->playerList[i]._pMaxMana);
playerData->set__plevel(data->playerList[i]._pLevel);
playerData->set__pexperience(data->playerList[i]._pExperience);
playerData->set__parmorclass(data->playerList[i]._pArmorClass);
playerData->set__pmagresist(data->playerList[i]._pMagResist);
playerData->set__pfireresist(data->playerList[i]._pFireResist);
playerData->set__plightresist(data->playerList[i]._pLightResist);
playerData->set__pgold(data->playerList[i]._pGold);
for (int j = 0; j < NUM_INVLOC; j++)
playerData->add_invbody(data->playerList[i].InvBody[j]);
for (int j = 0; j < MAXINV; j++)
playerData->add_invlist(data->playerList[i].InvList[j]);
for (int j = 0; j < MAXINV; j++)
playerData->add_invgrid(data->playerList[i].InvGrid[j]);
for (int j = 0; j < MAXSPD; j++)
playerData->add_spdlist(data->playerList[i].SpdList[j]);
playerData->set_holditem(data->playerList[i].HoldItem);
playerData->set__pimindam(data->playerList[i]._pIMinDam);
playerData->set__pimaxdam(data->playerList[i]._pIMaxDam);
playerData->set__pibonusdam(data->playerList[i]._pIBonusDam);
playerData->set__piac(data->playerList[i]._pIAC);
playerData->set__pibonustohit(data->playerList[i]._pIBonusToHit);
playerData->set__pibonusac(data->playerList[i]._pIBonusAC);
playerData->set__pibonusdammod(data->playerList[i]._pIBonusDamMod);
playerData->set_pmanashield(data->playerList[i].pManaShield);
}
auto emptyFillItemInfo = [&](int itemID, devilution::Item *item) {
itemsModified.push_back(itemID);
data->itemList[itemID].ID = itemID;
data->itemList[itemID]._iSeed = item->_iSeed;
data->itemList[itemID]._iCreateInfo = item->_iCreateInfo;
data->itemList[itemID]._itype = static_cast<int>(item->_itype);
data->itemList[itemID]._ix = -1;
data->itemList[itemID]._iy = -1;
data->itemList[itemID]._iIdentified = -1;
data->itemList[itemID]._iMagical = -1;
strcpy(data->itemList[itemID]._iName, "");
strcpy(data->itemList[itemID]._iIName, "");
data->itemList[itemID]._iFlags = -1;
data->itemList[itemID]._iPrePower = -1;
data->itemList[itemID]._iSufPower = -1;
data->itemList[itemID]._iPLDam = -1;
data->itemList[itemID]._iPLToHit = -1;
data->itemList[itemID]._iPLAC = -1;
data->itemList[itemID]._iPLStr = -1;
data->itemList[itemID]._iPLMag = -1;
data->itemList[itemID]._iPLDex = -1;
data->itemList[itemID]._iPLVit = -1;
data->itemList[itemID]._iPLFR = -1;
data->itemList[itemID]._iPLLR = -1;
data->itemList[itemID]._iPLMR = -1;
data->itemList[itemID]._iPLMana = -1;
data->itemList[itemID]._iPLHP = -1;
data->itemList[itemID]._iPLDamMod = -1;
data->itemList[itemID]._iPLGetHit = -1;
data->itemList[itemID]._iPLLight = -1;
data->itemList[itemID]._iSplLvlAdd = -1;
data->itemList[itemID]._iFMinDam = -1;
data->itemList[itemID]._iFMaxDam = -1;
data->itemList[itemID]._iLMinDam = -1;
data->itemList[itemID]._iLMaxDam = -1;
data->itemList[itemID]._iClass = -1;
data->itemList[itemID]._ivalue = -1;
data->itemList[itemID]._iMinDam = -1;
data->itemList[itemID]._iMaxDam = -1;
data->itemList[itemID]._iAC = -1;
data->itemList[itemID]._iMiscId = -1;
data->itemList[itemID]._iSpell = -1;
data->itemList[itemID]._iCharges = -1;
data->itemList[itemID]._iMaxCharges = -1;
data->itemList[itemID]._iDurability = -1;
data->itemList[itemID]._iMaxDur = -1;
data->itemList[itemID]._iMinStr = -1;
data->itemList[itemID]._iMinMag = -1;
data->itemList[itemID]._iMinDex = -1;
data->itemList[itemID]._iStatFlag = -1;
data->itemList[itemID].IDidx = item->IDidx;
};
for (int i = 0; i < devilution::ActiveItemCount; i++) {
int itemID = static_cast<int>(data->itemList.size());
for (int j = 0; j < data->itemList.size(); j++) {
if (data->itemList[j].compare(devilution::Items[devilution::ActiveItems[i]])) {
itemID = j;
break;
}
}
if (devilution::dItem[devilution::Items[devilution::ActiveItems[i]].position.x][devilution::Items[devilution::ActiveItems[i]].position.y] != static_cast<char>(devilution::ActiveItems[i] + 1))
continue;
if (itemID == data->itemList.size())
data->itemList.push_back(ItemData {});
int dx = devilution::Players[devilution::MyPlayerId].position.tile.x - devilution::Items[devilution::ActiveItems[i]].position.x;
int dy = devilution::Players[devilution::MyPlayerId].position.tile.y - devilution::Items[devilution::ActiveItems[i]].position.y;
if (dy > 0) {
if (dx < 1 && abs(dx) + abs(dy) < 11) {
partialFillItemInfo(itemID, &devilution::Items[devilution::ActiveItems[i]]);
data->groundItems.push_back(itemID);
} else if (dx > 0 && abs(dx) + abs(dy) < 12) {
partialFillItemInfo(itemID, &devilution::Items[devilution::ActiveItems[i]]);
data->groundItems.push_back(itemID);
} else
emptyFillItemInfo(itemID, &devilution::Items[devilution::ActiveItems[i]]);
} else {
if ((dx > -1 || dy == 0) && abs(dx) + abs(dy) < 11) {
partialFillItemInfo(itemID, &devilution::Items[devilution::ActiveItems[i]]);
data->groundItems.push_back(itemID);
} else if ((dx < 0 && dy != 0) && abs(dx) + abs(dy) < 12) {
partialFillItemInfo(itemID, &devilution::Items[devilution::ActiveItems[i]]);
data->groundItems.push_back(itemID);
} else
emptyFillItemInfo(itemID, &devilution::Items[devilution::ActiveItems[i]]);
}
}
data->storeItems.clear();
int storeLoopMax = 0;
devilution::Item *currentItem;
bool useiValue = false;
bool shiftValue = false;
switch (devilution::ActiveStore) {
case devilution::TalkID::StorytellerIdentify:
case devilution::TalkID::WitchSell:
case devilution::TalkID::WitchRecharge:
case devilution::TalkID::SmithSell:
case devilution::TalkID::SmithRepair:
storeLoopMax = 48;
currentItem = &devilution::PlayerItems[0];
useiValue = true;
break;
case devilution::TalkID::WitchBuy:
storeLoopMax = devilution::NumWitchItemsHf;
currentItem = &devilution::WitchItems[0];
break;
case devilution::TalkID::SmithBuy:
storeLoopMax = devilution::NumSmithBasicItemsHf;
currentItem = &devilution::SmithItems[0];
useiValue = true;
break;
case devilution::TalkID::HealerBuy:
storeLoopMax = devilution::NumHealerItemsHf;
currentItem = &devilution::HealerItems[0];
useiValue = true;
break;
case devilution::TalkID::SmithPremiumBuy:
storeLoopMax = devilution::NumSmithItemsHf;
currentItem = &devilution::PremiumItems[0];
break;
case devilution::TalkID::BoyBuy:
storeLoopMax = 1;
currentItem = &devilution::BoyItem;
shiftValue = true;
break;
}
for (int i = 0; i < storeLoopMax; i++) {
if (currentItem->_itype != devilution::ItemType::None) {
int itemID = static_cast<int>(data->itemList.size());
for (auto &item : data->itemList) {
if (item.compare(*currentItem)) {
itemID = item.ID;
break;
}
}
if (itemID == static_cast<int>(data->itemList.size())) {
data->itemList.push_back(ItemData {});
fullFillItemInfo(itemID, currentItem);
}
if (useiValue)
data->itemList[itemID]._ivalue = currentItem->_ivalue;
else if (shiftValue)
data->itemList[itemID]._ivalue = currentItem->_iIvalue + (currentItem->_iIvalue >> 1);
else
data->itemList[itemID]._ivalue = currentItem->_iIvalue;
if (data->itemList[itemID]._ivalue != 0) {
data->storeItems.push_back(itemID);
update->add_storeitems(itemID);
}
}
currentItem++;
}
if (devilution::currlevel != 0) {
for (auto &townerData : data->townerList) {
strcpy(townerData._tName, "");
townerData._tx = -1;
townerData._ty = -1;
}
} else {
for (auto i = 0; i < NUM_TOWNERS; i++) {
auto townerID = data->townerList.size();
for (int j = 0; j < data->townerList.size(); j++) {
if (data->townerList[j]._ttype == devilution::Towners[i]._ttype) {
townerID = j;
break;
}
}
if (townerID == data->townerList.size())
data->townerList.push_back(TownerData {});
data->townerList[townerID].ID = static_cast<int>(townerID);
if (isOnScreen(devilution::Towners[i].position.x, devilution::Towners[i].position.y)) {
data->townerList[townerID]._ttype = devilution::Towners[i]._ttype;
data->townerList[townerID]._tx = devilution::Towners[i].position.x;
data->townerList[townerID]._ty = devilution::Towners[i].position.y;
// might rework this and just change the type in data.
if (devilution::Towners[i].name.size() < 31) {
memcpy(data->townerList[townerID]._tName, devilution::Towners[i].name.data(), devilution::Towners[i].name.size());
data->townerList[townerID]._tName[devilution::Towners[i].name.size()] = '\0';
}
// strcpy(data->townerList[townerID]._tName, devilution::Towners[i].name); old code but with devilution subbed in for reference.
} else {
data->townerList[townerID]._ttype = static_cast<devilution::_talker_id>(devilution::Towners[i]._ttype);
data->townerList[townerID]._tx = -1;
data->townerList[townerID]._ty = -1;
strcpy(data->townerList[townerID]._tName, "");
}
}
}
for (auto &townie : data->townerList) {
auto townerData = update->add_townerdata();
townerData->set_id(townie.ID);
if (townie._tx != -1)
townerData->set__ttype(static_cast<int>(townie._ttype));
else
townerData->set__ttype(-1);
townerData->set__tx(townie._tx);
townerData->set__ty(townie._ty);
townerData->set__tname(townie._tName);
}
for (auto &itemID : itemsModified)
// for (auto& item : data->itemList)
{
auto &item = data->itemList[itemID];
auto itemData = update->add_itemdata();
itemData->set_id(item.ID);
itemData->set__itype(item._itype);
itemData->set__ix(item._ix);
itemData->set__iy(item._iy);
itemData->set__iidentified(item._iIdentified);
itemData->set__imagical(item._iMagical);
itemData->set__iname(item._iName);
itemData->set__iiname(item._iIName);
itemData->set__iclass(item._iClass);
itemData->set__icurs(item._iCurs);
itemData->set__ivalue(item._ivalue);
itemData->set__imindam(item._iMinDam);
itemData->set__imaxdam(item._iMaxDam);
itemData->set__iac(item._iAC);
itemData->set__iflags(item._iFlags);
itemData->set__imiscid(item._iMiscId);
itemData->set__ispell(item._iSpell);
itemData->set__icharges(item._iCharges);
itemData->set__imaxcharges(item._iMaxCharges);
itemData->set__idurability(item._iDurability);
itemData->set__imaxdur(item._iMaxDur);
itemData->set__ipldam(item._iPLDam);
itemData->set__ipltohit(item._iPLToHit);
itemData->set__iplac(item._iPLAC);
itemData->set__iplstr(item._iPLStr);
itemData->set__iplmag(item._iPLMag);
itemData->set__ipldex(item._iPLDex);
itemData->set__iplvit(item._iPLVit);
itemData->set__iplfr(item._iPLFR);
itemData->set__ipllr(item._iPLLR);
itemData->set__iplmr(item._iPLMR);
itemData->set__iplmana(item._iPLMana);
itemData->set__iplhp(item._iPLHP);
itemData->set__ipldammod(item._iPLDamMod);
itemData->set__iplgethit(item._iPLGetHit);
itemData->set__ipllight(item._iPLLight);
itemData->set__ispllvladd(item._iSplLvlAdd);
itemData->set__ifmindam(item._iFMinDam);
itemData->set__ifmaxdam(item._iFMaxDam);
itemData->set__ilmindam(item._iLMinDam);
itemData->set__ilmaxdam(item._iLMaxDam);
itemData->set__iprepower(item._iPrePower);
itemData->set__isufpower(item._iSufPower);
itemData->set__iminstr(item._iMinStr);
itemData->set__iminmag(item._iMinMag);
itemData->set__imindex(item._iMinDex);
itemData->set__istatflag(item._iStatFlag);
itemData->set_ididx(item.IDidx);
}
for (auto &itemID : data->groundItems)
update->add_grounditemid(itemID);
for (int i = 0; i < devilution::ActiveMonsterCount; i++) {
if (isOnScreen(devilution::Monsters[devilution::ActiveMonsters[i]].position.tile.x, devilution::Monsters[devilution::ActiveMonsters[i]].position.tile.y) && devilution::HasAnyOf(devilution::dFlags[devilution::Monsters[devilution::ActiveMonsters[i]].position.tile.x][devilution::Monsters[devilution::ActiveMonsters[i]].position.tile.y], devilution::DungeonFlag::Lit) && !(devilution::Monsters[devilution::ActiveMonsters[i]].flags & 0x01)) {
auto m = update->add_monsterdata();
m->set_index(devilution::ActiveMonsters[i]);
m->set_x(devilution::Monsters[devilution::ActiveMonsters[i]].position.tile.x);
m->set_y(devilution::Monsters[devilution::ActiveMonsters[i]].position.tile.y);
m->set_futx(devilution::Monsters[devilution::ActiveMonsters[i]].position.future.x);
m->set_futy(devilution::Monsters[devilution::ActiveMonsters[i]].position.future.y);
m->set_type(devilution::Monsters[devilution::ActiveMonsters[i]].type().type);
m->set_name(devilution::Monsters[devilution::ActiveMonsters[i]].data().name.c_str());
m->set_mode(static_cast<int>(devilution::Monsters[devilution::ActiveMonsters[i]].mode));
m->set_unique(static_cast<bool>(devilution::Monsters[devilution::ActiveMonsters[i]].isUnique()));
}
}
auto fillObject = [&](int index, devilution::Object &ob) {
auto o = update->add_objectdata();
o->set_type(ob._otype);
o->set_x(ob.position.x);
o->set_y(ob.position.y);
o->set_shrinetype(-1);
o->set_solid(ob._oSolidFlag);
o->set_doorstate(-1);
o->set_selectable(ob.selectionRegion != devilution::SelectionRegion::None ? true : false);
o->set_index(index);
switch (static_cast<devilution::_object_id>(ob._otype)) {
case devilution::_object_id::OBJ_BARRELEX:
o->set_type(static_cast<int>(devilution::_object_id::OBJ_BARREL));
break;
case devilution::_object_id::OBJ_SHRINEL:
case devilution::_object_id::OBJ_SHRINER:
if (ob.selectionRegion != devilution::SelectionRegion::None)
o->set_shrinetype(ob._oVar1);
break;
case devilution::_object_id::OBJ_L1LDOOR:
case devilution::_object_id::OBJ_L1RDOOR:
case devilution::_object_id::OBJ_L2LDOOR:
case devilution::_object_id::OBJ_L2RDOOR:
case devilution::_object_id::OBJ_L3LDOOR:
case devilution::_object_id::OBJ_L3RDOOR:
o->set_doorstate(ob._oVar4);
break;
}
if (devilution::Players[devilution::MyPlayerId]._pClass == devilution::HeroClass::Rogue)
o->set_trapped(ob._oTrapFlag);
else
o->set_trapped(false);
};
auto fillMissile = [&](devilution::Missile &ms) {
auto m = update->add_missiledata();
m->set_type(static_cast<int>(ms._mitype));
m->set_x(ms.position.tile.x);
m->set_y(ms.position.tile.y);
m->set_xvel(ms.position.velocity.deltaX);
m->set_yvel(ms.position.velocity.deltaY);
bool addSource = false;
switch (ms.sourceType()) {
case devilution::MissileSource::Monster:
if (isOnScreen(ms.sourceMonster()->position.tile.x, ms.sourceMonster()->position.tile.y)) {
m->set_sx(ms.sourceMonster()->position.tile.x);
m->set_sy(ms.sourceMonster()->position.tile.y);
} else {
m->set_sx(-1);
m->set_sy(-1);
}
break;
case devilution::MissileSource::Player:
if (isOnScreen(ms.sourcePlayer()->position.tile.x, ms.sourcePlayer()->position.tile.y)) {
m->set_sx(ms.sourcePlayer()->position.tile.x);
m->set_sy(ms.sourcePlayer()->position.tile.y);
} else {
m->set_sx(-1);
m->set_sy(-1);
}
break;
default:
m->set_sx(-1);
m->set_sy(-1);
}
};
if (devilution::Players[devilution::MyPlayerId].plrlevel != 0) {
for (int i = 0; i < devilution::ActiveObjectCount; i++) {
if (isOnScreen(devilution::Objects[devilution::ActiveObjects[i]].position.x, devilution::Objects[devilution::ActiveObjects[i]].position.y) && devilution::dObject[devilution::Objects[devilution::ActiveObjects[i]].position.x][devilution::Objects[devilution::ActiveObjects[i]].position.y] == devilution::ActiveObjects[i] + 1) {
fillObject(devilution::ActiveObjects[i], devilution::Objects[devilution::ActiveObjects[i]]);
}
}
for (auto& missile : devilution::Missiles) {
if (isOnScreen(missile.position.tile.x, missile.position.tile.y))
fillMissile(missile);
}
}
for (int i = 0; i < MAXPORTAL; i++) {
if (devilution::Portals[i].open && (devilution::Portals[i].level == devilution::Players[devilution::MyPlayerId].plrlevel) && isOnScreen(devilution::Portals[i].position.x, devilution::Portals[i].position.y)) {
auto tp = update->add_portaldata();
tp->set_x(devilution::Portals[i].position.x);
tp->set_y(devilution::Portals[i].position.y);
tp->set_player(i);
} else if (devilution::Portals[i].open && 0 == devilution::Players[devilution::MyPlayerId].plrlevel && isOnScreen(devilution::PortalTownPosition[i].x, devilution::PortalTownPosition[i].y)) {
auto tp = update->add_portaldata();
tp->set_x(devilution::PortalTownPosition[i].x);
tp->set_y(devilution::PortalTownPosition[i].y);
tp->set_player(i);
}
}
protoClient.queueMessage(std::move(message));
}
bool Server::isOnScreen(int x, int y)
{
bool returnValue = false;
int dx = data->playerList[data->player]._px - x;
int dy = data->playerList[data->player]._py - y;
if (!devilution::CharFlag) {
if (dy > 0) {
if (dx < 1 && abs(dx) + abs(dy) < 11)
returnValue = true;
else if (dx > 0 && abs(dx) + abs(dy) < 12)
returnValue = true;
} else {
if ((dx > -1 || dy == 0) && abs(dx) + abs(dy) < 11)
returnValue = true;
else if ((dx < 0 && dy != 0) && abs(dx) + abs(dy) < 12)
returnValue = true;
}
} else if (devilution::CharFlag) {
returnValue = panelScreenCheck[std::make_pair(dx, dy)];
}
return returnValue;
}
bool Server::OKToAct()
{
return !data->stextflag && data->pcurs == 1 && !data->qtextflag;
}
void Server::move(int x, int y)
{
devilution::NetSendCmdLoc(devilution::MyPlayerId, true, devilution::_cmd_id::CMD_WALKXY, devilution::Point { x, y });
}
void Server::talk(int x, int y)
{
int index;
for (index = 0; index < NUM_TOWNERS; index++) {
if (devilution::Towners[index].position.x == x && devilution::Towners[index].position.y == y)
break;
}
if (index != NUM_TOWNERS)
devilution::NetSendCmdLocParam1(true, devilution::_cmd_id::CMD_TALKXY, devilution::Point { x, y }, index);
}
void Server::selectStoreOption(StoreOption option)
{
switch (option) {
case StoreOption::TALK:
switch (devilution::ActiveStore) {
case devilution::TalkID::Witch:
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::OldTextLine = 12;
devilution::TownerId = devilution::_talker_id::TOWN_WITCH;
devilution::OldActiveStore = devilution::TalkID::Witch;
devilution::StartStore(devilution::TalkID::Gossip);
break;
}
case StoreOption::IDENTIFYANITEM:
if (devilution::ActiveStore == devilution::TalkID::Storyteller) {
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::StorytellerIdentify);
}
break;
case StoreOption::EXIT:
switch (devilution::ActiveStore) {
case devilution::TalkID::Barmaid:
case devilution::TalkID::Boy:
case devilution::TalkID::BoyBuy:
case devilution::TalkID::Drunk:
case devilution::TalkID::Healer:
case devilution::TalkID::Smith:
case devilution::TalkID::Storyteller:
case devilution::TalkID::Tavern:
case devilution::TalkID::Witch:
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::ActiveStore = devilution::TalkID::None;
}
break;
case StoreOption::BUYITEMS:
switch (devilution::ActiveStore) {
case devilution::TalkID::Witch:
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::WitchBuy);
break;
case devilution::TalkID::Healer:
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::HealerBuy);
break;
}
break;
case StoreOption::BUYBASIC:
if (devilution::ActiveStore == devilution::TalkID::Smith) {
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::SmithBuy);
}
break;
case StoreOption::BUYPREMIUM:
if (devilution::ActiveStore == devilution::TalkID::Smith) {
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::SmithPremiumBuy);
}
break;
case StoreOption::SELL:
switch (devilution::ActiveStore) {
case devilution::TalkID::Smith:
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::SmithSell);
break;
case devilution::TalkID::Witch:
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::WitchSell);
break;
}
break;
case StoreOption::REPAIR:
if (devilution::ActiveStore == devilution::TalkID::Smith) {
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::SmithRepair);
}
break;
case StoreOption::RECHARGE:
if (devilution::ActiveStore == devilution::TalkID::Witch) {
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::WitchRecharge);
}
break;
case StoreOption::WIRTPEEK:
if (devilution::ActiveStore == devilution::TalkID::Boy) {
if (50 <= devilution::Players[devilution::MyPlayerId]._pGold) {
devilution::TakePlrsMoney(50);
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::BoyBuy);
} else {
devilution::OldActiveStore = devilution::TalkID::Boy;
devilution::OldTextLine = 18;
devilution::OldScrollPos = devilution::ScrollPos;
devilution::StartStore(devilution::TalkID::NoMoney);
}
}
break;
case StoreOption::BACK:
switch (devilution::ActiveStore) {
case devilution::TalkID::SmithRepair:
case devilution::TalkID::SmithSell:
case devilution::TalkID::SmithBuy:
case devilution::TalkID::SmithPremiumBuy:
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::Smith);
break;
case devilution::TalkID::WitchBuy:
case devilution::TalkID::WitchSell:
case devilution::TalkID::WitchRecharge:
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::Witch);
break;
case devilution::TalkID::HealerBuy:
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::Healer);
break;
case devilution::TalkID::StorytellerIdentify:
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::StartStore(devilution::TalkID::Storyteller);
break;
}
}
}
void Server::buyItem(int itemID)
{
int idx;
if (devilution::ActiveStore == devilution::TalkID::WitchBuy) {
idx = -1;
for (int i = 0; i < 20; i++) {
if (data->itemList[itemID].compare(devilution::WitchItems[i])) {
idx = i;
break;
}
}
if (idx == -1)
return;
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::OldTextLine = devilution::CurrentTextLine;
devilution::OldScrollPos = devilution::ScrollPos;
devilution::OldActiveStore = devilution::ActiveStore;
if (!devilution::PlayerCanAfford(devilution::WitchItems[idx]._iIvalue)) {
devilution::StartStore(devilution::TalkID::NoMoney);
return;
} else if (devilution::StoreAutoPlace(devilution::WitchItems[idx], true)) {
if (idx < 3)
devilution::WitchItems[idx]._iSeed = devilution::AdvanceRndSeed();
devilution::TakePlrsMoney(devilution::Players[devilution::MyPlayerId].HoldItem._iIvalue);
if (idx >= 3) {
if (idx == devilution::NumWitchItemsHf - 1)
devilution::WitchItems[devilution::NumWitchItemsHf - 1].clear();
else {
for (; !devilution::WitchItems[idx + 1].isEmpty(); idx++) {
devilution::WitchItems[idx] = std::move(devilution::WitchItems[idx + 1]);
}
devilution::WitchItems[idx].clear();
}
}
devilution::CalcPlrInv(*devilution::MyPlayer, true);
} else {
devilution::StartStore(devilution::TalkID::NoRoom);
return;
}
devilution::StartStore(devilution::OldActiveStore);
} else if (devilution::ActiveStore == devilution::TalkID::SmithBuy) {
idx = -1;
for (int i = 0; i < 20; i++) {
if (data->itemList[itemID].compare(devilution::SmithItems[i])) {
idx = i;
break;
}
}
if (idx == -1)
return;
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::OldTextLine = devilution::CurrentTextLine;
devilution::OldScrollPos = devilution::ScrollPos;
devilution::OldActiveStore = devilution::TalkID::SmithBuy;
if (!devilution::PlayerCanAfford(devilution::SmithItems[idx]._iIvalue)) {
devilution::StartStore(devilution::TalkID::NoMoney);
return;
} else if (!devilution::StoreAutoPlace(devilution::SmithItems[idx], false)) {
devilution::StartStore(devilution::TalkID::NoRoom);
} else {
devilution::TakePlrsMoney(devilution::SmithItems[idx]._iIvalue);
if (devilution::SmithItems[idx]._iMagical == devilution::item_quality::ITEM_QUALITY_NORMAL)
devilution::SmithItems[idx]._iIdentified = false;
devilution::StoreAutoPlace(devilution::SmithItems[idx], true);
if (idx == devilution::NumSmithBasicItemsHf - 1) {
devilution::SmithItems[devilution::NumSmithBasicItemsHf - 1].clear();
} else {
for (; !devilution::SmithItems[idx + 1].isEmpty(); idx++) {
devilution::SmithItems[idx] = std::move(devilution::SmithItems[idx + 1]);
}
devilution::SmithItems[idx].clear();
}
devilution::CalcPlrInv(*devilution::MyPlayer, true);
devilution::StartStore(devilution::OldActiveStore);
}
} else if (devilution::ActiveStore == devilution::TalkID::SmithPremiumBuy) {
int idx = -1;
for (int i = 0; i < 20; i++) {
if (data->itemList[itemID].compare(devilution::PremiumItems[i])) {
idx = i;
break;
}
}
if (idx == -1)
return;
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::OldTextLine = devilution::CurrentTextLine;
devilution::OldScrollPos = devilution::ScrollPos;
devilution::OldActiveStore = devilution::TalkID::SmithBuy;
if (!devilution::PlayerCanAfford(devilution::PremiumItems[idx]._iIvalue)) {
devilution::StartStore(devilution::TalkID::NoMoney);
return;
} else if (!devilution::StoreAutoPlace(devilution::PremiumItems[idx], false)) {
devilution::StartStore(devilution::TalkID::NoRoom);
return;
} else {
devilution::TakePlrsMoney(devilution::PremiumItems[idx]._iIvalue);
if (devilution::PremiumItems[idx]._iMagical == devilution::item_quality::ITEM_QUALITY_NORMAL)
devilution::PremiumItems[idx]._iIdentified = false;
devilution::StoreAutoPlace(devilution::PremiumItems[idx], true);
if (idx == devilution::NumSmithBasicItemsHf - 1) {
devilution::PremiumItems[devilution::NumSmithBasicItemsHf - 1].clear();
} else {
for (; !devilution::PremiumItems[idx + 1].isEmpty(); idx++) {
devilution::PremiumItems[idx] = std::move(devilution::PremiumItems[idx + 1]);
}
devilution::PremiumItems[idx].clear();
}
devilution::CalcPlrInv(*devilution::MyPlayer, true);
devilution::StartStore(devilution::OldActiveStore);
}
} else if (devilution::ActiveStore == devilution::TalkID::HealerBuy) {
idx = -1;
for (int i = 0; i < 20; i++) {
if (data->itemList[itemID].compare(devilution::HealerItems[i])) {
idx = i;
break;
}
}
if (idx == -1)
return;
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::OldTextLine = devilution::CurrentTextLine;
devilution::OldScrollPos = devilution::ScrollPos;
devilution::OldActiveStore = devilution::TalkID::HealerBuy;
if (!devilution::PlayerCanAfford(devilution::HealerItems[idx]._iIvalue)) {
devilution::StartStore(devilution::TalkID::NoMoney);
return;
} else if (!devilution::StoreAutoPlace(devilution::HealerItems[idx], false)) {
devilution::StartStore(devilution::TalkID::NoRoom);
return;
} else {
if (!devilution::gbIsMultiplayer) {
if (idx < 2)
devilution::HealerItems[idx]._iSeed = devilution::AdvanceRndSeed();
} else {
if (idx < 3)
devilution::HealerItems[idx]._iSeed = devilution::AdvanceRndSeed();
}
devilution::TakePlrsMoney(devilution::HealerItems[idx]._iIvalue);
if (devilution::HealerItems[idx]._iMagical == devilution::item_quality::ITEM_QUALITY_NORMAL)
devilution::HealerItems[idx]._iIdentified = false;
devilution::StoreAutoPlace(devilution::HealerItems[idx], true);
if (!devilution::gbIsMultiplayer) {
if (idx < 2)
return;
} else {
if (idx < 3)
return;
}
}
if (idx == 19) {
devilution::HealerItems[19].clear();
} else {
for (; !devilution::HealerItems[idx + 1].isEmpty(); idx++) {
devilution::HealerItems[idx] = std::move(devilution::HealerItems[idx + 1]);
}
devilution::HealerItems[idx].clear();
}
CalcPlrInv(*devilution::MyPlayer, true);
devilution::StartStore(devilution::OldActiveStore);
} else if (devilution::ActiveStore == devilution::TalkID::BoyBuy) {
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::OldActiveStore = devilution::TalkID::BoyBuy;
devilution::OldScrollPos = devilution::ScrollPos;
devilution::OldTextLine = 10;
int price = devilution::BoyItem._iIvalue;
if (devilution::gbIsHellfire)
price -= devilution::BoyItem._iIvalue / 4;
else
price += devilution::BoyItem._iIvalue / 2;
if (!devilution::PlayerCanAfford(price)) {
devilution::StartStore(devilution::TalkID::NoMoney);
return;
} else if (!devilution::StoreAutoPlace(devilution::BoyItem, false)) {
devilution::StartStore(devilution::TalkID::NoRoom);
return;
} else {
devilution::TakePlrsMoney(price);
devilution::StoreAutoPlace(devilution::BoyItem, true);
devilution::BoyItem.clear();
devilution::OldActiveStore = devilution::TalkID::Boy;
devilution::OldTextLine = 12;
}
devilution::StartStore(devilution::OldActiveStore);
}
}
void Server::sellItem(int itemID)
{
int idx;
if (devilution::ActiveStore != devilution::TalkID::WitchSell &&devilution::ActiveStore != devilution::TalkID::SmithSell)
return;
idx = -1;
for (int i = 0; i < 48; i++) {
if (data->itemList[itemID].compare(devilution::PlayerItems[i])) {
idx = i;
break;
}
}
if (idx == -1)
return;
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::OldTextLine = devilution::CurrentTextLine;
devilution::OldActiveStore = devilution::TalkID::SmithSell;
devilution::OldScrollPos = devilution::ScrollPos;
if (!devilution::StoreGoldFit(devilution::PlayerItems[idx])) {
devilution::StartStore(devilution::TalkID::NoRoom);
return;
}
devilution::Player &myPlayer = *devilution::MyPlayer;
if (devilution::PlayerItemIndexes[idx] >= 0)
myPlayer.RemoveInvItem(devilution::PlayerItemIndexes[idx]);
else
myPlayer.RemoveSpdBarItem(-(devilution::PlayerItemIndexes[idx] + 1));
int cost = devilution::PlayerItems[idx]._iIvalue;
devilution::CurrentItemIndex--;
if (idx != devilution::CurrentItemIndex) {
while (idx < devilution::CurrentItemIndex) {
devilution::PlayerItems[idx] = devilution::PlayerItems[idx + 1];
devilution::PlayerItemIndexes[idx] = devilution::PlayerItemIndexes[idx + 1];
idx++;
}
}
devilution::AddGoldToInventory(myPlayer, cost);
myPlayer._pGold += cost;
devilution::StartStore(devilution::OldActiveStore);
}
void Server::rechargeItem(int itemID)
{
int idx;
if (devilution::ActiveStore != devilution::TalkID::WitchRecharge)
return;
idx = -1;
for (int i = 0; i < 20; i++) {
if (data->itemList[itemID].compare(devilution::PlayerItems[i])) {
idx = i;
break;
}
}
if (idx == -1)
return;
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::OldActiveStore = devilution::TalkID::WitchRecharge;
devilution::OldTextLine = devilution::CurrentTextLine;
devilution::OldScrollPos = devilution::ScrollPos;
int price = devilution::PlayerItems[idx]._iIvalue;
if (!devilution::PlayerCanAfford(price)) {
devilution::StartStore(devilution::TalkID::NoMoney);
return;
} else {
devilution::PlayerItems[idx]._iCharges = devilution::PlayerItems[idx]._iMaxCharges;
devilution::Player &myPlayer = *devilution::MyPlayer;
int8_t i = devilution::PlayerItemIndexes[idx];
if (i < 0) {
myPlayer.InvBody[devilution::inv_body_loc::INVLOC_HAND_LEFT]._iCharges = myPlayer.InvBody[devilution::inv_body_loc::INVLOC_HAND_LEFT]._iMaxCharges;
devilution::NetSendCmdChItem(true, devilution::inv_body_loc::INVLOC_HAND_LEFT);
} else {
myPlayer.InvList[i]._iCharges = myPlayer.InvList[i]._iMaxCharges;
devilution::NetSyncInvItem(myPlayer, i);
}
devilution::TakePlrsMoney(price);
devilution::CalcPlrInv(myPlayer, true);
devilution::StartStore(devilution::OldActiveStore);
}
}
void Server::repairItem(int itemID)
{
int idx;
if (devilution::ActiveStore != devilution::TalkID::SmithRepair)
return;
idx = -1;
for (int i = 0; i < 20; i++) {
if (data->itemList[itemID].compare(devilution::PlayerItems[i])) {
idx = i;
break;
}
}
if (idx == -1)
return;
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::OldActiveStore = devilution::TalkID::SmithRepair;
devilution::OldTextLine = devilution::CurrentTextLine;
devilution::OldScrollPos = devilution::ScrollPos;
int price = devilution::PlayerItems[idx]._iIvalue;
if (!devilution::PlayerCanAfford(price)) {
devilution::StartStore(devilution::TalkID::NoMoney);
return;
}
devilution::PlayerItems[idx]._iDurability = devilution::PlayerItems[idx]._iMaxDur;
int8_t i = devilution::PlayerItemIndexes[idx];
devilution::Player &myPlayer = *devilution::MyPlayer;
if (i < 0) {
if (i == -1)
myPlayer.InvBody[devilution::inv_body_loc::INVLOC_HEAD]._iDurability = myPlayer.InvBody[devilution::inv_body_loc::INVLOC_HEAD]._iMaxDur;
if (i == -2)
myPlayer.InvBody[devilution::inv_body_loc::INVLOC_CHEST]._iDurability = myPlayer.InvBody[devilution::inv_body_loc::INVLOC_CHEST]._iMaxDur;
if (i == -3)
myPlayer.InvBody[devilution::inv_body_loc::INVLOC_HAND_LEFT]._iDurability = myPlayer.InvBody[devilution::inv_body_loc::INVLOC_HAND_LEFT]._iMaxDur;
if (i == -4)
myPlayer.InvBody[devilution::inv_body_loc::INVLOC_HAND_RIGHT]._iDurability = myPlayer.InvBody[devilution::inv_body_loc::INVLOC_HAND_RIGHT]._iMaxDur;
devilution::TakePlrsMoney(price);
devilution::StartStore(devilution::OldActiveStore);
}
myPlayer.InvList[i]._iDurability = myPlayer.InvList[i]._iMaxDur;
devilution::TakePlrsMoney(price);
devilution::StartStore(devilution::OldActiveStore);
}
void Server::attackMonster(int index)
{
if (index < 0 || 199 < index)
return;
if (!OKToAct())
return;
if (!isOnScreen(devilution::Monsters[index].position.tile.x, devilution::Monsters[index].position.tile.y))
return;
if (devilution::M_Talker(devilution::Monsters[index]))
devilution::NetSendCmdParam1(true, devilution::_cmd_id::CMD_ATTACKID, index);
else if (devilution::Players[devilution::MyPlayerId].InvBody[devilution::inv_body_loc::INVLOC_HAND_LEFT]._itype == devilution::ItemType::Bow || devilution::Players[devilution::MyPlayerId].InvBody[devilution::inv_body_loc::INVLOC_HAND_RIGHT]._itype == devilution::ItemType::Bow)
devilution::NetSendCmdParam1(true, devilution::_cmd_id::CMD_RATTACKID, index);
else
devilution::NetSendCmdParam1(true, devilution::_cmd_id::CMD_ATTACKID, index);
}
void Server::attackXY(int x, int y)
{
if (!isOnScreen(x, y))
return;
if (!OKToAct())
return;
if (devilution::Players[devilution::MyPlayerId].InvBody[devilution::inv_body_loc::INVLOC_HAND_LEFT]._itype == devilution::ItemType::Bow || devilution::Players[devilution::MyPlayerId].InvBody[devilution::inv_body_loc::INVLOC_HAND_RIGHT]._itype == devilution::ItemType::Bow)
devilution::NetSendCmdLoc(devilution::MyPlayerId, true, devilution::_cmd_id::CMD_RATTACKXY, devilution::Point { x, y });
else
devilution::NetSendCmdLoc(devilution::MyPlayerId, true, devilution::_cmd_id::CMD_SATTACKXY, devilution::Point { x, y });
}
void Server::operateObject(int index)
{
if (index < 0 || 126 < index)
return;
if (!isOnScreen(devilution::Objects[index].position.x, devilution::Objects[index].position.y))
return;
if (!OKToAct())
return;
bool found = false;
for (int i = 0; i < devilution::ActiveObjectCount; i++) {
if (devilution::ActiveObjects[i] == index) {
found = true;
break;
}
}
if (!found)
return;
devilution::NetSendCmdLocParam1(true, devilution::_cmd_id::CMD_OPOBJXY, devilution::Point { devilution::Objects[index].position.x, devilution::Objects[index].position.y }, index);
}
void Server::useBeltItem(int slot)
{
if (slot < 0 || 7 < slot)
return;
if (devilution::Players[devilution::MyPlayerId].SpdList[slot]._itype == devilution::ItemType::None)
return;
int cii = slot + 47;
devilution::UseInvItem(cii);
}
void Server::toggleCharacterScreen()
{
if (!OKToAct())
return;
devilution::CharFlag = !devilution::CharFlag;
}
void Server::increaseStat(CommandType commandType)
{
int maxValue = 0;
if (devilution::Players[devilution::MyPlayerId]._pStatPts == 0)
return;
switch (commandType) {
case CommandType::ADDSTR:
switch (static_cast<devilution::HeroClass>(devilution::Players[devilution::MyPlayerId]._pClass)) {
case devilution::HeroClass::Warrior:
maxValue = 250;
break;
case devilution::HeroClass::Rogue:
maxValue = 55;
break;
case devilution::HeroClass::Sorcerer:
maxValue = 45;
break;
}
if (devilution::Players[devilution::MyPlayerId]._pBaseStr < maxValue) {
devilution::NetSendCmdParam1(true, devilution::_cmd_id::CMD_ADDSTR, 1);
devilution::Players[devilution::MyPlayerId]._pStatPts -= 1;
}
break;
case CommandType::ADDMAG:
switch (static_cast<devilution::HeroClass>(devilution::Players[devilution::MyPlayerId]._pClass)) {
case devilution::HeroClass::Warrior:
maxValue = 50;
break;
case devilution::HeroClass::Rogue:
maxValue = 70;
break;
case devilution::HeroClass::Sorcerer:
maxValue = 250;
break;
}
if (devilution::Players[devilution::MyPlayerId]._pBaseMag < maxValue) {
devilution::NetSendCmdParam1(true, devilution::_cmd_id::CMD_ADDMAG, 1);
devilution::Players[devilution::MyPlayerId]._pStatPts -= 1;
}
break;
case CommandType::ADDDEX:
switch (static_cast<devilution::HeroClass>(devilution::Players[devilution::MyPlayerId]._pClass)) {
case devilution::HeroClass::Warrior:
maxValue = 60;
break;
case devilution::HeroClass::Rogue:
maxValue = 250;
break;
case devilution::HeroClass::Sorcerer:
maxValue = 85;
break;
}
if (devilution::Players[devilution::MyPlayerId]._pBaseDex < maxValue) {
devilution::NetSendCmdParam1(true, devilution::_cmd_id::CMD_ADDDEX, 1);
devilution::Players[devilution::MyPlayerId]._pStatPts -= 1;
}
break;
case CommandType::ADDVIT:
switch (static_cast<devilution::HeroClass>(devilution::Players[devilution::MyPlayerId]._pClass)) {
case devilution::HeroClass::Warrior:
maxValue = 100;
break;
case devilution::HeroClass::Rogue:
maxValue = 80;
break;
case devilution::HeroClass::Sorcerer:
maxValue = 80;
break;
}
if (devilution::Players[devilution::MyPlayerId]._pBaseVit < maxValue) {
devilution::NetSendCmdParam1(true, devilution::_cmd_id::CMD_ADDVIT, 1);
devilution::Players[devilution::MyPlayerId]._pStatPts -= 1;
}
}
}
void Server::getItem(int itemID)
{
if (!OKToAct())
return;
bool found = false;
for (auto i = 0; i < data->groundItems.size(); i++) {
if (data->groundItems[i] == itemID)
found = true;
if (found)
break;
}
if (!found)
return;
auto itemData = data->itemList[itemID];
if (!isOnScreen(itemData._ix, itemData._iy))
return;
int index = -1;
for (int i = 0; i < devilution::ActiveItemCount; i++) {
if (itemData.compare(devilution::Items[devilution::ActiveItems[i]]))
index = devilution::ActiveItems[i];
if (index != -1)
break;
}
if (index == -1)
return;
if (devilution::invflag)
devilution::NetSendCmdLocParam1(true, devilution::_cmd_id::CMD_GOTOGETITEM, devilution::Point { itemData._ix, itemData._iy }, index);
else
devilution::NetSendCmdLocParam1(true, devilution::_cmd_id::CMD_GOTOAGETITEM, devilution::Point { itemData._ix, itemData._iy }, index);
}
void Server::setSpell(int spellID, devilution::SpellType spellType)
{
if (spellID == -1)
return;
switch (spellType) {
case devilution::SpellType::Skill:
if (!(devilution::Players[devilution::MyPlayerId]._pAblSpells & (1 << (spellID - 1))))
return;
break;
case devilution::SpellType::Spell:
if (!(devilution::Players[devilution::MyPlayerId]._pMemSpells & (1 << (spellID - 1))))
return;
break;
case devilution::SpellType::Scroll:
if (!(devilution::Players[devilution::MyPlayerId]._pScrlSpells & (1 << (spellID - 1))))
return;
break;
case devilution::SpellType::Charges:
if ((devilution::Players[devilution::MyPlayerId].InvBody[4]._iSpell != static_cast<devilution::SpellID>(spellID) && devilution::Players[devilution::MyPlayerId].InvBody[5]._iSpell != static_cast<devilution::SpellID>(spellID)) || (devilution::Players[devilution::MyPlayerId].InvBody[4]._iCharges == 0 && devilution::Players[devilution::MyPlayerId].InvBody[5]._iCharges == 0))
return;
break;
case devilution::SpellType::Invalid:
default:
return;
break;
}
devilution::Players[devilution::MyPlayerId]._pRSpell = static_cast<devilution::SpellID>(spellID);
devilution::Players[devilution::MyPlayerId]._pRSplType = static_cast<devilution::SpellType>(spellType);
//*force_redraw = 255; // TODO: Is this line needed in devilutionX? If so, what is it?
}
void Server::castSpell(int index)
{
if (!OKToAct())
return;
devilution::pcursmonst = index;
devilution::PlayerUnderCursor = nullptr;
devilution::cursPosition = devilution::Point { devilution::Monsters[index].position.tile.x, devilution::Monsters[index].position.tile.y };
devilution::CheckPlrSpell(false);
}
void Server::toggleInventory()
{
if (!OKToAct())
return;
devilution::invflag = !devilution::invflag;
}
void Server::putInCursor(int itemID)
{
if (!OKToAct())
return;
if (data->itemList.size() <= itemID)
return;
auto item = data->itemList[itemID];
int mx, my;
mx = 0;
my = 0;
for (int i = 0; i < 55; i++) {
if (i < 7) {
if (item.compare(devilution::Players[devilution::MyPlayerId].InvBody[i]) && devilution::Players[devilution::MyPlayerId].InvBody[i]._itype != devilution::ItemType::None) {
if (!devilution::invflag)
return;
switch (static_cast<EquipSlot>(i)) {
case EquipSlot::HEAD:
mx = devilution::InvRect[0].position.x + 1;
my = devilution::InvRect[0].position.y - 1;
break;
case EquipSlot::LEFTRING:
mx = devilution::InvRect[4].position.x + 1;
my = devilution::InvRect[4].position.y - 1;
break;
case EquipSlot::RIGHTRING:
mx = devilution::InvRect[5].position.x + 1;
my = devilution::InvRect[5].position.y - 1;
break;
case EquipSlot::AMULET:
mx = devilution::InvRect[6].position.x + 1;
my = devilution::InvRect[6].position.y - 1;
break;
case EquipSlot::LEFTHAND:
mx = devilution::InvRect[7].position.x + 1;
my = devilution::InvRect[7].position.y - 1;
break;
case EquipSlot::RIGHTHAND:
mx = devilution::InvRect[13].position.x + 1;
my = devilution::InvRect[13].position.y - 1;
break;
case EquipSlot::BODY:
mx = devilution::InvRect[19].position.x + 1;
my = devilution::InvRect[19].position.y - 1;
break;
}
break;
}
} else if (i < 47) {
if (item.compare(devilution::Players[devilution::MyPlayerId].InvList[i - 7]) && devilution::Players[devilution::MyPlayerId].InvList[i - 7]._itype != devilution::ItemType::None && i - 7 < devilution::Players[devilution::MyPlayerId]._pNumInv) {
if (!devilution::invflag)
return;
for (int rect_index = 0; rect_index < 40; rect_index++) {
if (devilution::Players[devilution::MyPlayerId].InvGrid[rect_index] == i - 6) {
int index = rect_index + 25;
mx = devilution::InvRect[index].position.x + 1;
my = devilution::InvRect[index].position.y - 1;
break;
}
}
break;
}
} else {
if (item.compare(devilution::Players[devilution::MyPlayerId].SpdList[i - 47]) && devilution::Players[devilution::MyPlayerId].SpdList[i - 47]._itype != devilution::ItemType::None) {
int index = 18 + i;
mx = 210 + (i - 47) * 30;
my = 370;
break;
}
}
}
if (mx != 0 && my != 0)
devilution::CheckInvCut(*devilution::MyPlayer, devilution::Point { mx, my }, false, false);
}
void Server::putCursorItem(int location)
{
int mx, my;
EquipSlot equipLocation = static_cast<EquipSlot>(location);
if (!data->invflag)
return;
if (12 <= data->pcurs && equipLocation <= EquipSlot::BELT8) {
mx = 0;
my = 0;
switch (equipLocation) {
case EquipSlot::HEAD:
mx = devilution::InvRect[0].position.x + 1;
my = devilution::InvRect[0].position.y - 1;
break;
case EquipSlot::LEFTRING:
mx = devilution::InvRect[4].position.x + 2;
my = devilution::InvRect[4].position.y - 20;
break;
case EquipSlot::RIGHTRING:
mx = devilution::InvRect[5].position.x + 2;
my = devilution::InvRect[5].position.y - 20;
break;
case EquipSlot::AMULET:
mx = devilution::InvRect[6].position.x + 2;
my = devilution::InvRect[6].position.y - 20;
break;
case EquipSlot::LEFTHAND:
mx = devilution::InvRect[7].position.x + 1;
my = devilution::InvRect[7].position.y - 1;
break;
case EquipSlot::RIGHTHAND:
mx = devilution::InvRect[13].position.x + 1;
my = devilution::InvRect[13].position.y - 1;
break;
case EquipSlot::BODY:
mx = devilution::InvRect[19].position.x + 1;
my = devilution::InvRect[19].position.y - 1;
break;
default:
if (equipLocation < EquipSlot::BELT1) {
int index = 18 + location;
mx = devilution::InvRect[index].position.x + 2;
my = devilution::InvRect[index].position.y - 20;
} else {
int index = 18 + location;
mx = 210 + (location - 47) * 30;
my = 370;
}
break;
}
devilution::CheckInvPaste(*devilution::MyPlayer, devilution::Point { mx, my });
}
}
void Server::dropCursorItem()
{
if (!isOnScreen(devilution::Players[devilution::MyPlayerId].position.tile.x, devilution::Players[devilution::MyPlayerId].position.tile.y))
return;
if (12 <= data->pcurs) {
devilution::NetSendCmdPItem(true, devilution::_cmd_id::CMD_PUTITEM, devilution::Point { devilution::Players[devilution::MyPlayerId].position.tile.x, devilution::Players[devilution::MyPlayerId].position.tile.y }, devilution::MyPlayer->HoldItem);
devilution::NewCursor(devilution::cursor_id::CURSOR_HAND);
}
}
void Server::useItem(int itemID)
{
if (!OKToAct())
return;
if (data->itemList.size() <= itemID)
return;
auto itemData = data->itemList[itemID];
for (int i = 0; i < 8; i++) {
if (devilution::Players[devilution::MyPlayerId].SpdList[i]._itype != devilution::ItemType::None && itemData.compare(devilution::Players[devilution::MyPlayerId].SpdList[i])) {
useBeltItem(i);
return;
}
}
for (int i = 0; i < devilution::Players[devilution::MyPlayerId]._pNumInv; i++) {
if (devilution::Players[devilution::MyPlayerId].InvList[i]._itype != devilution::ItemType::None && itemData.compare(devilution::Players[devilution::MyPlayerId].InvList[i])) {
devilution::UseInvItem(i + 7);
return;
}
}
}
void Server::identifyStoreItem(int itemID)
{
int id;
if (devilution::ActiveStore != devilution::TalkID::StorytellerIdentify)
return;
id = -1;
for (int i = 0; i < 20; i++) {
if (data->itemList[itemID].compare(devilution::PlayerItems[i])) {
id = i;
break;
}
}
if (id == -1)
return;
devilution::PlaySFX(devilution::SfxID::MenuSelect);
devilution::OldActiveStore = devilution::TalkID::StorytellerIdentify;
devilution::OldTextLine = devilution::CurrentTextLine;
devilution::OldScrollPos = devilution::ScrollPos;
if (!devilution::PlayerCanAfford(devilution::PlayerItems[id]._iIvalue)) {
devilution::StartStore(devilution::TalkID::NoMoney);
return;
} else {
devilution::Player &myPlayer = *devilution::MyPlayer;
int idx = devilution::PlayerItemIndexes[idx];
if (idx < 0) {
if (idx == -1)
myPlayer.InvBody[devilution::INVLOC_HEAD]._iIdentified = true;
if (idx == -2)
myPlayer.InvBody[devilution::INVLOC_CHEST]._iIdentified = true;
if (idx == -3)
myPlayer.InvBody[devilution::INVLOC_HAND_LEFT]._iIdentified = true;
if (idx == -4)
myPlayer.InvBody[devilution::INVLOC_HAND_RIGHT]._iIdentified = true;
if (idx == -5)
myPlayer.InvBody[devilution::INVLOC_RING_LEFT]._iIdentified = true;
if (idx == -6)
myPlayer.InvBody[devilution::INVLOC_RING_RIGHT]._iIdentified = true;
if (idx == -7)
myPlayer.InvBody[devilution::INVLOC_AMULET]._iIdentified = true;
} else {
myPlayer.InvList[idx]._iIdentified = true;
}
devilution::PlayerItems[id]._iIdentified = true;
devilution::TakePlrsMoney(devilution::PlayerItems[id]._iIvalue);
devilution::CalcPlrInv(myPlayer, true);
}
}
void Server::castSpell(int x, int y)
{
if (!OKToAct())
return;
if (!isOnScreen(x, y))
return;
devilution::pcursmonst = -1;
devilution::PlayerUnderCursor = nullptr;
devilution::cursPosition = devilution::Point { x, y };
devilution::CheckPlrSpell(false);
}
void Server::cancelQText()
{
if (!data->qtextflag)
return;
devilution::qtextflag = false;
data->qtextflag = false;
devilution::stream_stop();
}
void Server::setFPS(int newFPS)
{
FPS = newFPS;
}
void Server::disarmTrap(int index)
{
if (data->pcurs != devilution::cursor_id::CURSOR_DISARM)
return;
if (static_cast<devilution::HeroClass>(data->playerList[data->player]._pClass) != devilution::HeroClass::Rogue)
return;
devilution::NetSendCmdLocParam1(true, devilution::_cmd_id::CMD_DISARMXY, devilution::Point { devilution::Objects[index].position.x, devilution::Objects[index].position.y }, index);
}
void Server::skillRepair(int itemID)
{
if (data->pcurs != devilution::cursor_id::CURSOR_REPAIR)
return;
if (static_cast<devilution::HeroClass>(data->playerList[data->player]._pClass) != devilution::HeroClass::Warrior)
return;
if (!data->invflag)
return;
for (int i = 0; i < 7; i++) {
if (data->itemList[itemID].compare(devilution::Players[devilution::MyPlayerId].InvBody[i])) {
devilution::DoRepair(*devilution::MyPlayer, i);
return;
}
}
for (int i = 0; i < MAXINV; i++) {
if (data->itemList[itemID].compare(devilution::Players[devilution::MyPlayerId].InvList[i])) {
devilution::DoRepair(*devilution::MyPlayer, i + 7);
return;
}
}
}
void Server::skillRecharge(int itemID)
{
if (static_cast<devilution::cursor_id>(data->pcurs) != devilution::cursor_id::CURSOR_RECHARGE)
return;
if (static_cast<devilution::HeroClass>(data->playerList[data->player]._pClass) != devilution::HeroClass::Sorcerer)
return;
for (int i = 0; i < 7; i++) {
if (data->itemList[itemID].compare(devilution::Players[devilution::MyPlayerId].InvBody[i])) {
devilution::DoRecharge(*devilution::MyPlayer, i);
return;
}
}
for (int i = 0; i < MAXINV; i++) {
if (data->itemList[itemID].compare(devilution::Players[devilution::MyPlayerId].InvList[i])) {
devilution::DoRecharge(*devilution::MyPlayer, i + 7);
return;
}
}
}
void Server::toggleMenu()
{
devilution::qtextflag = false;
if (!devilution::gmenu_is_active())
devilution::gamemenu_on();
else
devilution::gamemenu_off();
return;
}
void Server::saveGame()
{
if (devilution::gbIsMultiplayer || !devilution::gmenu_is_active())
return;
devilution::gmenu_presskeys(SDLK_KP_ENTER);
return;
}
void Server::quit()
{
if (!devilution::gmenu_is_active())
return;
devilution::gmenu_presskeys(SDLK_UP);
devilution::gmenu_presskeys(SDLK_KP_ENTER);
return;
}
void Server::clearCursor()
{
if (devilution::pcurs == static_cast<int>(devilution::cursor_id::CURSOR_REPAIR) || devilution::pcurs == static_cast<int>(devilution::cursor_id::CURSOR_DISARM) || devilution::pcurs == static_cast<int>(devilution::cursor_id::CURSOR_RECHARGE) || devilution::pcurs == static_cast<int>(devilution::cursor_id::CURSOR_IDENTIFY))
devilution::NewCursor(devilution::cursor_id::CURSOR_HAND);
return;
}
void Server::identifyItem(int itemID)
{
if (static_cast<devilution::cursor_id>(data->pcurs) != devilution::cursor_id::CURSOR_IDENTIFY)
return;
if (!data->invflag)
return;
for (int i = 0; i < 7; i++) {
if (data->itemList[itemID].compare(devilution::Players[devilution::MyPlayerId].InvBody[i])) {
devilution::CheckIdentify(*devilution::MyPlayer, i);
return;
}
}
for (int i = 0; i < MAXINV; i++) {
if (data->itemList[itemID].compare(devilution::Players[devilution::MyPlayerId].InvList[i])) {
devilution::CheckIdentify(*devilution::MyPlayer, i + 7);
return;
}
}
}
} // namespace DAPI