introduce offline training scripts

This commit is contained in:
ErikasKontenis
2020-11-07 14:32:53 +02:00
parent 093ac51d31
commit 33d9dd7dcd
12 changed files with 378 additions and 5 deletions

View File

@@ -190,7 +190,7 @@ bool IOLoginData::preloadPlayer(Player* player, const std::string& name)
bool IOLoginData::loadPlayerById(Player* player, uint32_t id)
{
std::ostringstream query;
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id;
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id;
return loadPlayer(player, Database::getInstance()->storeQuery(query.str()));
}
@@ -198,7 +198,7 @@ bool IOLoginData::loadPlayerByName(Player* player, const std::string& name)
{
Database* db = Database::getInstance();
std::ostringstream query;
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name);
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name);
return loadPlayer(player, db->storeQuery(query.str()));
}
@@ -321,6 +321,9 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
player->lastLoginSaved = result->getNumber<time_t>("lastlogin");
player->lastLogout = result->getNumber<time_t>("lastlogout");
player->offlineTrainingTime = result->getNumber<int32_t>("offlinetraining_time") * 1000;
player->offlineTrainingSkill = result->getNumber<int32_t>("offlinetraining_skill");
Town* town = g_game.map.towns.getTown(result->getNumber<uint32_t>("town_id"));
if (!town) {
std::cout << "[Error - IOLoginData::loadPlayer] " << player->name << " has Town ID " << result->getNumber<uint32_t>("town_id") << " which doesn't exist" << std::endl;
@@ -660,6 +663,8 @@ bool IOLoginData::savePlayer(Player* player)
query << "`lastlogout` = " << player->getLastLogout() << ',';
query << "`balance` = " << player->bankBalance << ',';
query << "`offlinetraining_time` = " << player->getOfflineTrainingTime() / 1000 << ',';
query << "`offlinetraining_skill` = " << player->getOfflineTrainingSkill() << ',';
query << "`stamina` = " << player->getStaminaMinutes() << ',';
query << "`skill_fist` = " << player->skills[SKILL_FIST].level << ',';

View File

@@ -2008,6 +2008,15 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Player", "getSkillTries", LuaScriptInterface::luaPlayerGetSkillTries);
registerMethod("Player", "addSkillTries", LuaScriptInterface::luaPlayerAddSkillTries);
registerMethod("Player", "addOfflineTrainingTime", LuaScriptInterface::luaPlayerAddOfflineTrainingTime);
registerMethod("Player", "getOfflineTrainingTime", LuaScriptInterface::luaPlayerGetOfflineTrainingTime);
registerMethod("Player", "removeOfflineTrainingTime", LuaScriptInterface::luaPlayerRemoveOfflineTrainingTime);
registerMethod("Player", "addOfflineTrainingTries", LuaScriptInterface::luaPlayerAddOfflineTrainingTries);
registerMethod("Player", "getOfflineTrainingSkill", LuaScriptInterface::luaPlayerGetOfflineTrainingSkill);
registerMethod("Player", "setOfflineTrainingSkill", LuaScriptInterface::luaPlayerSetOfflineTrainingSkill);
registerMethod("Player", "getItemCount", LuaScriptInterface::luaPlayerGetItemCount);
registerMethod("Player", "getItemById", LuaScriptInterface::luaPlayerGetItemById);
@@ -7530,6 +7539,95 @@ int LuaScriptInterface::luaPlayerAddSkillTries(lua_State* L)
return 1;
}
int LuaScriptInterface::luaPlayerAddOfflineTrainingTime(lua_State* L)
{
// player:addOfflineTrainingTime(time)
Player* player = getUserdata<Player>(L, 1);
if (player) {
int32_t time = getNumber<int32_t>(L, 2);
player->addOfflineTrainingTime(time);
player->sendStats();
pushBoolean(L, true);
}
else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaPlayerGetOfflineTrainingTime(lua_State* L)
{
// player:getOfflineTrainingTime()
Player* player = getUserdata<Player>(L, 1);
if (player) {
lua_pushnumber(L, player->getOfflineTrainingTime());
}
else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaPlayerRemoveOfflineTrainingTime(lua_State* L)
{
// player:removeOfflineTrainingTime(time)
Player* player = getUserdata<Player>(L, 1);
if (player) {
int32_t time = getNumber<int32_t>(L, 2);
player->removeOfflineTrainingTime(time);
player->sendStats();
pushBoolean(L, true);
}
else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaPlayerAddOfflineTrainingTries(lua_State* L)
{
// player:addOfflineTrainingTries(skillType, tries)
Player* player = getUserdata<Player>(L, 1);
if (player) {
skills_t skillType = getNumber<skills_t>(L, 2);
uint64_t tries = getNumber<uint64_t>(L, 3);
pushBoolean(L, player->addOfflineTrainingTries(skillType, tries));
}
else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaPlayerGetOfflineTrainingSkill(lua_State* L)
{
// player:getOfflineTrainingSkill()
Player* player = getUserdata<Player>(L, 1);
if (player) {
lua_pushnumber(L, player->getOfflineTrainingSkill());
}
else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaPlayerSetOfflineTrainingSkill(lua_State* L)
{
// player:setOfflineTrainingSkill(skillId)
Player* player = getUserdata<Player>(L, 1);
if (player) {
uint32_t skillId = getNumber<uint32_t>(L, 2);
player->setOfflineTrainingSkill(skillId);
pushBoolean(L, true);
}
else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaPlayerGetItemCount(lua_State* L)
{
// player:getItemCount(itemId[, subType = -1])

View File

@@ -833,6 +833,15 @@ class LuaScriptInterface
static int luaPlayerGetSkillTries(lua_State* L);
static int luaPlayerAddSkillTries(lua_State* L);
static int luaPlayerAddOfflineTrainingTime(lua_State* L);
static int luaPlayerGetOfflineTrainingTime(lua_State* L);
static int luaPlayerRemoveOfflineTrainingTime(lua_State* L);
static int luaPlayerAddOfflineTrainingTries(lua_State* L);
static int luaPlayerGetOfflineTrainingSkill(lua_State* L);
static int luaPlayerSetOfflineTrainingSkill(lua_State* L);
static int luaPlayerGetItemCount(lua_State* L);
static int luaPlayerGetItemById(lua_State* L);

View File

@@ -1194,6 +1194,8 @@ void Player::onThink(uint32_t interval)
if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) {
checkSkullTicks();
}
addOfflineTrainingTime(interval);
}
uint32_t Player::isMuted() const
@@ -3737,6 +3739,141 @@ void Player::sendClosePrivate(uint16_t channelId)
}
}
bool Player::addOfflineTrainingTries(skills_t skill, uint64_t tries)
{
if (tries == 0 || skill == SKILL_LEVEL) {
return false;
}
bool sendUpdate = false;
uint32_t oldSkillValue, newSkillValue;
long double oldPercentToNextLevel, newPercentToNextLevel;
if (skill == SKILL_MAGLEVEL) {
uint64_t currReqMana = vocation->getReqMana(magLevel);
uint64_t nextReqMana = vocation->getReqMana(magLevel + 1);
if (currReqMana >= nextReqMana) {
return false;
}
oldSkillValue = magLevel;
oldPercentToNextLevel = static_cast<long double>(manaSpent * 100) / nextReqMana;
g_events->eventPlayerOnGainSkillTries(this, SKILL_MAGLEVEL, tries);
uint32_t currMagLevel = magLevel;
while ((manaSpent + tries) >= nextReqMana) {
tries -= nextReqMana - manaSpent;
magLevel++;
manaSpent = 0;
g_creatureEvents->playerAdvance(this, SKILL_MAGLEVEL, magLevel - 1, magLevel);
sendUpdate = true;
currReqMana = nextReqMana;
nextReqMana = vocation->getReqMana(magLevel + 1);
if (currReqMana >= nextReqMana) {
tries = 0;
break;
}
}
manaSpent += tries;
if (magLevel != currMagLevel) {
std::ostringstream ss;
ss << "You advanced to magic level " << magLevel << '.';
sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str());
}
uint8_t newPercent;
if (nextReqMana > currReqMana) {
newPercent = Player::getPercentLevel(manaSpent, nextReqMana);
newPercentToNextLevel = static_cast<long double>(manaSpent * 100) / nextReqMana;
}
else {
newPercent = 0;
newPercentToNextLevel = 0;
}
if (newPercent != magLevelPercent) {
magLevelPercent = newPercent;
sendUpdate = true;
}
newSkillValue = magLevel;
}
else {
uint64_t currReqTries = vocation->getReqSkillTries(skill, skills[skill].level);
uint64_t nextReqTries = vocation->getReqSkillTries(skill, skills[skill].level + 1);
if (currReqTries >= nextReqTries) {
return false;
}
oldSkillValue = skills[skill].level;
oldPercentToNextLevel = static_cast<long double>(skills[skill].tries * 100) / nextReqTries;
g_events->eventPlayerOnGainSkillTries(this, skill, tries);
uint32_t currSkillLevel = skills[skill].level;
while ((skills[skill].tries + tries) >= nextReqTries) {
tries -= nextReqTries - skills[skill].tries;
skills[skill].level++;
skills[skill].tries = 0;
skills[skill].percent = 0;
g_creatureEvents->playerAdvance(this, skill, (skills[skill].level - 1), skills[skill].level);
sendUpdate = true;
currReqTries = nextReqTries;
nextReqTries = vocation->getReqSkillTries(skill, skills[skill].level + 1);
if (currReqTries >= nextReqTries) {
tries = 0;
break;
}
}
skills[skill].tries += tries;
if (currSkillLevel != skills[skill].level) {
std::ostringstream ss;
ss << "You advanced to " << getSkillName(skill) << " level " << skills[skill].level << '.';
sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str());
}
uint8_t newPercent;
if (nextReqTries > currReqTries) {
newPercent = Player::getPercentLevel(skills[skill].tries, nextReqTries);
newPercentToNextLevel = static_cast<long double>(skills[skill].tries * 100) / nextReqTries;
}
else {
newPercent = 0;
newPercentToNextLevel = 0;
}
if (skills[skill].percent != newPercent) {
skills[skill].percent = newPercent;
sendUpdate = true;
}
newSkillValue = skills[skill].level;
}
if (sendUpdate) {
sendSkills();
}
std::ostringstream ss;
ss << std::fixed << std::setprecision(2) << "Your " << ucwords(getSkillName(skill)) << " skill changed from level " << oldSkillValue << " (with " << oldPercentToNextLevel << "% progress towards level " << (oldSkillValue + 1) << ") to level " << newSkillValue << " (with " << newPercentToNextLevel << "% progress towards level " << (newSkillValue + 1) << ')';
sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str());
return sendUpdate;
}
uint64_t Player::getMoney() const
{
std::vector<const Container*> containers;

View File

@@ -154,6 +154,25 @@ class Player final : public Creature, public Cylinder
return staminaMinutes;
}
bool addOfflineTrainingTries(skills_t skill, uint64_t tries);
void addOfflineTrainingTime(int32_t addTime) {
offlineTrainingTime = std::min<int32_t>(12 * 3600 * 1000, offlineTrainingTime + addTime);
}
void removeOfflineTrainingTime(int32_t removeTime) {
offlineTrainingTime = std::max<int32_t>(0, offlineTrainingTime - removeTime);
}
int32_t getOfflineTrainingTime() const {
return offlineTrainingTime;
}
int32_t getOfflineTrainingSkill() const {
return offlineTrainingSkill;
}
void setOfflineTrainingSkill(int32_t skill) {
offlineTrainingSkill = skill;
}
uint64_t getBankBalance() const {
return bankBalance;
}
@@ -1069,6 +1088,8 @@ class Player final : public Creature, public Cylinder
int32_t premiumDays = 0;
int32_t bloodHitCount = 0;
int32_t shieldBlockCount = 0;
int32_t offlineTrainingSkill = -1;
int32_t offlineTrainingTime = 0;
int32_t idleTime = 0;
int32_t lastWalkingTime = 0;