mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-22 13:30:06 +00:00
Variable damage to/from mobs
* Player weapons and armor ratings are taken into account when damaging/getting damaged by mobs. * Players have a 5% chance to critical strike mobs, this doubles the player's weapon power. * Aside from player and mob stat based damage variance, there is also an inherent 20% variance to any damage.
This commit is contained in:
parent
b4fb449e69
commit
4fea2ae896
@ -123,6 +123,9 @@ void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
// send equip event to other players
|
// send equip event to other players
|
||||||
PlayerManager::sendToViewable(sock, (void*)&equipChange, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE));
|
PlayerManager::sendToViewable(sock, (void*)&equipChange, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE));
|
||||||
|
|
||||||
|
// set equipment stats serverside
|
||||||
|
setItemStats(plr.plr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send response
|
// send response
|
||||||
@ -859,3 +862,19 @@ void ItemManager::checkItemExpire(CNSocket* sock, Player* player) {
|
|||||||
player->toRemoveVehicle.eIL = 0;
|
player->toRemoveVehicle.eIL = 0;
|
||||||
player->toRemoveVehicle.iSlotNum = 0;
|
player->toRemoveVehicle.iSlotNum = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItemManager::setItemStats(Player* plr) {
|
||||||
|
|
||||||
|
plr->pointDamage = 8 + plr->level * 2;
|
||||||
|
plr->groupDamage = 8 + plr->level * 2;
|
||||||
|
plr->defense = 16 + plr->level * 4;
|
||||||
|
|
||||||
|
Item* itemStatsDat;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
itemStatsDat = ItemManager::getItemData(plr->Equip[i].iID, plr->Equip[i].iType);
|
||||||
|
plr->pointDamage += itemStatsDat->pointDamage;
|
||||||
|
plr->groupDamage += itemStatsDat->groupDamage;
|
||||||
|
plr->defense += itemStatsDat->defense;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
struct Item {
|
struct Item {
|
||||||
bool tradeable, sellable;
|
bool tradeable, sellable;
|
||||||
int buyPrice, sellPrice, stackSize, level, rarity; // TODO: implement more as needed
|
int buyPrice, sellPrice, stackSize, level, rarity, pointDamage, groupDamage, defense; // TODO: implement more as needed
|
||||||
};
|
};
|
||||||
struct VendorListing {
|
struct VendorListing {
|
||||||
int sort, type, iID;
|
int sort, type, iID;
|
||||||
@ -49,4 +49,5 @@ namespace ItemManager {
|
|||||||
int findFreeSlot(Player *plr);
|
int findFreeSlot(Player *plr);
|
||||||
Item* getItemData(int32_t id, int32_t type);
|
Item* getItemData(int32_t id, int32_t type);
|
||||||
void checkItemExpire(CNSocket* sock, Player* player);
|
void checkItemExpire(CNSocket* sock, Player* player);
|
||||||
|
void setItemStats(Player* plr);
|
||||||
}
|
}
|
||||||
|
@ -61,12 +61,19 @@ void MobManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
|
|||||||
}
|
}
|
||||||
Mob *mob = Mobs[pktdata[i]];
|
Mob *mob = Mobs[pktdata[i]];
|
||||||
|
|
||||||
int damage = hitMob(sock, mob, 150);
|
std::pair<int,int> damage;
|
||||||
|
|
||||||
|
if (pkt->iNPCCnt > 1)
|
||||||
|
damage = getDamage(plr->groupDamage, (int)mob->data["m_iProtection"], true);
|
||||||
|
else
|
||||||
|
damage = getDamage(plr->pointDamage, (int)mob->data["m_iProtection"], true);
|
||||||
|
|
||||||
|
damage.first = hitMob(sock, mob, damage.first);
|
||||||
|
|
||||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
||||||
respdata[i].iDamage = damage;
|
respdata[i].iDamage = damage.first;
|
||||||
respdata[i].iHP = mob->appearanceData.iHP;
|
respdata[i].iHP = mob->appearanceData.iHP;
|
||||||
respdata[i].iHitFlag = 2; // hitscan, not a rocket or a grenade
|
respdata[i].iHitFlag = damage.second; // hitscan, not a rocket or a grenade
|
||||||
}
|
}
|
||||||
|
|
||||||
sock->sendPacket((void*)respbuf, P_FE2CL_PC_ATTACK_NPCs_SUCC, resplen);
|
sock->sendPacket((void*)respbuf, P_FE2CL_PC_ATTACK_NPCs_SUCC, resplen);
|
||||||
@ -93,15 +100,16 @@ void MobManager::npcAttackPc(Mob *mob) {
|
|||||||
sP_FE2CL_NPC_ATTACK_PCs *pkt = (sP_FE2CL_NPC_ATTACK_PCs*)respbuf;
|
sP_FE2CL_NPC_ATTACK_PCs *pkt = (sP_FE2CL_NPC_ATTACK_PCs*)respbuf;
|
||||||
sAttackResult *atk = (sAttackResult*)(respbuf + sizeof(sP_FE2CL_NPC_ATTACK_PCs));
|
sAttackResult *atk = (sAttackResult*)(respbuf + sizeof(sP_FE2CL_NPC_ATTACK_PCs));
|
||||||
|
|
||||||
plr->HP += (int)mob->data["m_iPower"]; // already negative
|
auto damage = getDamage(440 + (int)mob->data["m_iPower"], plr->defense, false);
|
||||||
|
plr->HP -= damage.first;
|
||||||
|
|
||||||
pkt->iNPC_ID = mob->appearanceData.iNPC_ID;
|
pkt->iNPC_ID = mob->appearanceData.iNPC_ID;
|
||||||
pkt->iPCCnt = 1;
|
pkt->iPCCnt = 1;
|
||||||
|
|
||||||
atk->iID = plr->iID;
|
atk->iID = plr->iID;
|
||||||
atk->iDamage = -(int)mob->data["m_iPower"];
|
atk->iDamage = damage.first;
|
||||||
atk->iHP = plr->HP;
|
atk->iHP = plr->HP;
|
||||||
atk->iHitFlag = 2;
|
atk->iHitFlag = damage.second;
|
||||||
|
|
||||||
mob->target->sendPacket((void*)respbuf, P_FE2CL_NPC_ATTACK_PCs, resplen);
|
mob->target->sendPacket((void*)respbuf, P_FE2CL_NPC_ATTACK_PCs, resplen);
|
||||||
PlayerManager::sendToViewable(mob->target, (void*)respbuf, P_FE2CL_NPC_ATTACK_PCs, resplen);
|
PlayerManager::sendToViewable(mob->target, (void*)respbuf, P_FE2CL_NPC_ATTACK_PCs, resplen);
|
||||||
@ -564,3 +572,20 @@ void MobManager::playerTick(CNServer *serv, time_t currTime) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<int,int> MobManager::getDamage(int attackPower, int defensePower, bool shouldCrit) {
|
||||||
|
|
||||||
|
std::pair<int,int> ret = {};
|
||||||
|
|
||||||
|
int damage = attackPower * (rand() % 40 + 80) / 100; // 20% variance
|
||||||
|
ret.second = 1;
|
||||||
|
|
||||||
|
if (shouldCrit && rand() % 20 == 0) {
|
||||||
|
damage *= 2; // critical hit
|
||||||
|
ret.second = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.first = std::max(std::min(damage, damage * damage / defensePower / 4), std::min(damage * damage / defensePower / 2, damage - defensePower));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
@ -104,4 +104,5 @@ namespace MobManager {
|
|||||||
void killMob(CNSocket *sock, Mob *mob);
|
void killMob(CNSocket *sock, Mob *mob);
|
||||||
void giveReward(CNSocket *sock);
|
void giveReward(CNSocket *sock);
|
||||||
std::pair<int,int> lerp(int, int, int, int, int);
|
std::pair<int,int> lerp(int, int, int, int, int);
|
||||||
|
std::pair<int,int> getDamage(int, int, bool);
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,10 @@ struct Player {
|
|||||||
|
|
||||||
bool inCombat;
|
bool inCombat;
|
||||||
bool dotDamage;
|
bool dotDamage;
|
||||||
|
|
||||||
|
int pointDamage;
|
||||||
|
int groupDamage;
|
||||||
|
int defense;
|
||||||
|
|
||||||
int64_t aQuestFlag[16];
|
int64_t aQuestFlag[16];
|
||||||
int tasks[ACTIVE_MISSION_COUNT];
|
int tasks[ACTIVE_MISSION_COUNT];
|
||||||
|
@ -316,6 +316,9 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
|
|||||||
addPlayer(sock, plr);
|
addPlayer(sock, plr);
|
||||||
//check if there is an expiring vehicle
|
//check if there is an expiring vehicle
|
||||||
ItemManager::checkItemExpire(sock, getPlayer(sock));
|
ItemManager::checkItemExpire(sock, getPlayer(sock));
|
||||||
|
|
||||||
|
//set player equip stats
|
||||||
|
ItemManager::setItemStats(getPlayer(sock));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerManager::sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size) {
|
void PlayerManager::sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size) {
|
||||||
|
@ -117,8 +117,7 @@ void TableData::init() {
|
|||||||
auto item = _item.value();
|
auto item = _item.value();
|
||||||
int typeOverride = getItemType(i); // used for special cases where iEquipLoc doesn't indicate item type
|
int typeOverride = getItemType(i); // used for special cases where iEquipLoc doesn't indicate item type
|
||||||
ItemManager::ItemData[std::pair<int32_t, int32_t>(item["m_iItemNumber"], typeOverride != -1 ? typeOverride : (int)item["m_iEquipLoc"])]
|
ItemManager::ItemData[std::pair<int32_t, int32_t>(item["m_iItemNumber"], typeOverride != -1 ? typeOverride : (int)item["m_iEquipLoc"])]
|
||||||
= { item["m_iTradeAble"] == 1, item["m_iSellAble"] == 1, item["m_iItemPrice"], item["m_iItemSellPrice"], item["m_iStackNumber"], i > 9 ? 0 : (int)item["m_iMinReqLev"],
|
= { item["m_iTradeAble"] == 1, item["m_iSellAble"] == 1, item["m_iItemPrice"], item["m_iItemSellPrice"], item["m_iStackNumber"], i > 9 ? 0 : (int)item["m_iMinReqLev"], i > 9 ? 1 : (int)item["m_iRarity"], i > 9 ? 0 : (int)item["m_iPointRat"], i > 9 ? 0 : (int)item["m_iGroupRat"], i > 9 ? 0 : (int)item["m_iDefenseRat"] };
|
||||||
i > 9 ? 1 : (int)item["m_iRarity"] };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user