mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-22 21:40:05 +00:00
UnsummonW Implementation + Tweaks
* UnsummonW can be used to remove the mob from existence. * Mob groups now aggro together. * Mobs space a little bit when chasing the player. * Combat balance tweaked a bit, you can take out an entire boss group of scoria cephalopod with good nano usage with common tier weapons.
This commit is contained in:
parent
5e8b6eec6e
commit
f1d04cec01
@ -284,6 +284,22 @@ void unsummonWCommand(std::string full, std::vector<std::string>& args, CNSocket
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int leadId = ((Mob*)npc)->groupLeader;
|
||||||
|
if (leadId != 0) {
|
||||||
|
Mob* leadNpc = MobManager::Mobs[leadId];
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (leadNpc->groupMember[i] == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
TableData::RunningMobs.erase(leadNpc->groupMember[i]);
|
||||||
|
NPCManager::destroyNPC(leadNpc->groupMember[i]);
|
||||||
|
}
|
||||||
|
TableData::RunningMobs.erase(leadId);
|
||||||
|
NPCManager::destroyNPC(leadId);
|
||||||
|
ChatManager::sendServerMessage(sock, "/unsummonW: Mob group destroyed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ChatManager::sendServerMessage(sock, "/unsummonW: removed mob with type: " + std::to_string(npc->appearanceData.iNPCType) +
|
ChatManager::sendServerMessage(sock, "/unsummonW: removed mob with type: " + std::to_string(npc->appearanceData.iNPCType) +
|
||||||
", id: " + std::to_string(npc->appearanceData.iNPC_ID));
|
", id: " + std::to_string(npc->appearanceData.iNPC_ID));
|
||||||
|
|
||||||
@ -509,11 +525,11 @@ void notifyCommand(std::string full, std::vector<std::string>& args, CNSocket* s
|
|||||||
Player *plr = PlayerManager::getPlayer(sock);
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
if (plr->notify) {
|
if (plr->notify) {
|
||||||
plr->notify = false;
|
plr->notify = false;
|
||||||
ChatManager::sendServerMessage(sock, "[ADMIN] No longer receiving join notifications");
|
ChatManager::sendServerMessage(sock, "[ADMIN] No longer receiving join notifications");
|
||||||
} else {
|
} else {
|
||||||
plr->notify = true;
|
plr->notify = true;
|
||||||
ChatManager::sendServerMessage(sock, "[ADMIN] Receiving join notifications");
|
ChatManager::sendServerMessage(sock, "[ADMIN] Receiving join notifications");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,14 +539,16 @@ void playersCommand(std::string full, std::vector<std::string>& args, CNSocket*
|
|||||||
ChatManager::sendServerMessage(sock, PlayerManager::getPlayerName(pair.second));
|
ChatManager::sendServerMessage(sock, PlayerManager::getPlayerName(pair.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
void summonGroupWCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
void summonGroupCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
if (args.size() < 4) {
|
if (args.size() < 4) {
|
||||||
ChatManager::sendServerMessage(sock, "/summonGroupW <leadermob> <mob> <number> [distance]");
|
ChatManager::sendServerMessage(sock, "/summonGroup(W) <leadermob> <mob> <number> [distance]");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Player* plr = PlayerManager::getPlayer(sock);
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
char *rest;
|
char *rest;
|
||||||
|
|
||||||
|
bool wCommand = (args[0] == "/summonGroupW");
|
||||||
int type = std::strtol(args[1].c_str(), &rest, 10);
|
int type = std::strtol(args[1].c_str(), &rest, 10);
|
||||||
int type2 = std::strtol(args[2].c_str(), &rest, 10);
|
int type2 = std::strtol(args[2].c_str(), &rest, 10);
|
||||||
int count = std::strtol(args[3].c_str(), &rest, 10);
|
int count = std::strtol(args[3].c_str(), &rest, 10);
|
||||||
@ -586,7 +604,8 @@ void summonGroupWCommand(std::string full, std::vector<std::string>& args, CNSoc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// re-enable respawning
|
// re-enable respawning
|
||||||
((Mob*)npc)->summoned = false;
|
if (wCommand)
|
||||||
|
((Mob*)npc)->summoned = false;
|
||||||
} else {
|
} else {
|
||||||
npc = new BaseNPC(x, y, z + EXTRA_HEIGHT, 0, plr->instanceID, type, id);
|
npc = new BaseNPC(x, y, z + EXTRA_HEIGHT, 0, plr->instanceID, type, id);
|
||||||
}
|
}
|
||||||
@ -612,8 +631,8 @@ void summonGroupWCommand(std::string full, std::vector<std::string>& args, CNSoc
|
|||||||
mob->offsetX = x - plr->x;
|
mob->offsetX = x - plr->x;
|
||||||
mob->offsetY = y - plr->y;
|
mob->offsetY = y - plr->y;
|
||||||
}
|
}
|
||||||
|
if (wCommand)
|
||||||
((Mob*)npc)->summoned = false;
|
((Mob*)npc)->summoned = false;
|
||||||
} else {
|
} else {
|
||||||
npc = new BaseNPC(x, y, z + EXTRA_HEIGHT, 0, MAPNUM(plr->instanceID), type, id);
|
npc = new BaseNPC(x, y, z + EXTRA_HEIGHT, 0, MAPNUM(plr->instanceID), type, id);
|
||||||
}
|
}
|
||||||
@ -624,9 +643,10 @@ void summonGroupWCommand(std::string full, std::vector<std::string>& args, CNSoc
|
|||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, x, y, z);
|
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatManager::sendServerMessage(sock, "/summonGroupW: placed mob with type: " + std::to_string(type) +
|
ChatManager::sendServerMessage(sock, "/summonGroup(W): placed mob with type: " + std::to_string(type) +
|
||||||
", id: " + std::to_string(npc->appearanceData.iNPC_ID));
|
", id: " + std::to_string(npc->appearanceData.iNPC_ID));
|
||||||
TableData::RunningMobs[npc->appearanceData.iNPC_ID] = npc; // only record the one in the template
|
if (wCommand)
|
||||||
|
TableData::RunningMobs[npc->appearanceData.iNPC_ID] = npc; // only record the one in the template
|
||||||
|
|
||||||
if (i == 0 && team == 2) {
|
if (i == 0 && team == 2) {
|
||||||
type = type2;
|
type = type2;
|
||||||
@ -666,7 +686,8 @@ void ChatManager::init() {
|
|||||||
registerCommand("tasks", 30, tasksCommand, "list all active missions and their respective task ids.");
|
registerCommand("tasks", 30, tasksCommand, "list all active missions and their respective task ids.");
|
||||||
registerCommand("notify", 30, notifyCommand, "receive a message whenever a player joins the server");
|
registerCommand("notify", 30, notifyCommand, "receive a message whenever a player joins the server");
|
||||||
registerCommand("players", 30, playersCommand, "print all players on the server");
|
registerCommand("players", 30, playersCommand, "print all players on the server");
|
||||||
registerCommand("summonGroupW", 30, summonGroupWCommand, "permanently summon group NPCs");
|
registerCommand("summonGroup", 30, summonGroupCommand, "summon group NPCs");
|
||||||
|
registerCommand("summonGroupW", 30, summonGroupCommand, "permanently summon group NPCs");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatManager::registerCommand(std::string cmd, int requiredLevel, CommandHandler handlr, std::string help) {
|
void ChatManager::registerCommand(std::string cmd, int requiredLevel, CommandHandler handlr, std::string help) {
|
||||||
|
@ -133,7 +133,7 @@ void MobManager::npcAttackPc(Mob *mob, time_t currTime) {
|
|||||||
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));
|
||||||
|
|
||||||
auto damage = getDamage(450 + (int)mob->data["m_iPower"], plr->defense, false, false, -1, -1, rand() % plr->level + 1);
|
auto damage = getDamage(450 + (int)mob->data["m_iPower"], plr->defense, false, false, -1, -1, 0);
|
||||||
plr->HP -= damage.first;
|
plr->HP -= damage.first;
|
||||||
|
|
||||||
pkt->iNPC_ID = mob->appearanceData.iNPC_ID;
|
pkt->iNPC_ID = mob->appearanceData.iNPC_ID;
|
||||||
@ -338,6 +338,9 @@ int MobManager::hitMob(CNSocket *sock, Mob *mob, int damage) {
|
|||||||
mob->roamX = mob->appearanceData.iX;
|
mob->roamX = mob->appearanceData.iX;
|
||||||
mob->roamY = mob->appearanceData.iY;
|
mob->roamY = mob->appearanceData.iY;
|
||||||
mob->roamZ = mob->appearanceData.iZ;
|
mob->roamZ = mob->appearanceData.iZ;
|
||||||
|
|
||||||
|
if (mob->groupLeader != 0)
|
||||||
|
followToCombat(mob);
|
||||||
}
|
}
|
||||||
|
|
||||||
mob->appearanceData.iHP -= damage;
|
mob->appearanceData.iHP -= damage;
|
||||||
@ -560,7 +563,14 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
|||||||
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED)
|
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED)
|
||||||
speed /= 2;
|
speed /= 2;
|
||||||
|
|
||||||
auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, mob->target->plr->x, mob->target->plr->y,std::min(distance-(int)mob->data["m_iAtkRange"]+1, speed*2/5));
|
int targetX = mob->target->plr->x;
|
||||||
|
int targetY = mob->target->plr->y;
|
||||||
|
if (mob->groupLeader != 0) {
|
||||||
|
targetX += mob->offsetX*distance/(mob->sightRange+1);
|
||||||
|
targetY += mob->offsetY*distance/(mob->sightRange+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, targetX, targetY, std::min(distance-(int)mob->data["m_iAtkRange"]+1, speed*2/5));
|
||||||
|
|
||||||
NPCManager::updateNPCPosition(mob->appearanceData.iNPC_ID, targ.first, targ.second, mob->appearanceData.iZ, mob->instanceID, mob->appearanceData.iAngle);
|
NPCManager::updateNPCPosition(mob->appearanceData.iNPC_ID, targ.first, targ.second, mob->appearanceData.iZ, mob->instanceID, mob->appearanceData.iAngle);
|
||||||
|
|
||||||
@ -570,10 +580,6 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
|||||||
pkt.iSpeed = speed;
|
pkt.iSpeed = speed;
|
||||||
pkt.iToX = mob->appearanceData.iX = targ.first;
|
pkt.iToX = mob->appearanceData.iX = targ.first;
|
||||||
pkt.iToY = mob->appearanceData.iY = targ.second;
|
pkt.iToY = mob->appearanceData.iY = targ.second;
|
||||||
if (mob->groupLeader != 0 && mob->groupLeader != mob->appearanceData.iNPC_ID) {
|
|
||||||
pkt.iToX += mob->offsetX;
|
|
||||||
pkt.iToY += mob->offsetY;
|
|
||||||
}
|
|
||||||
pkt.iToZ = mob->target->plr->z;
|
pkt.iToZ = mob->target->plr->z;
|
||||||
pkt.iMoveStyle = 1;
|
pkt.iMoveStyle = 1;
|
||||||
|
|
||||||
@ -972,7 +978,7 @@ std::pair<int,int> MobManager::getDamage(int attackPower, int defensePower, bool
|
|||||||
|
|
||||||
// base calculation
|
// base calculation
|
||||||
int damage = attackPower * attackPower / (attackPower + defensePower);
|
int damage = attackPower * attackPower / (attackPower + defensePower);
|
||||||
//damage = std::max(10 + attackPower / 10, damage - defensePower * (4 + difficulty) / 100);
|
damage = std::max(10 + attackPower / 10, damage - (defensePower - attackPower / 2) * difficulty / 72);
|
||||||
damage = damage * (rand() % 40 + 80) / 100;
|
damage = damage * (rand() % 40 + 80) / 100;
|
||||||
|
|
||||||
// Adaptium/Blastons/Cosmix
|
// Adaptium/Blastons/Cosmix
|
||||||
@ -1053,7 +1059,7 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
|||||||
else
|
else
|
||||||
damage.first = plr->pointDamage;
|
damage.first = plr->pointDamage;
|
||||||
|
|
||||||
damage = getDamage(damage.first, target->defense, true, (plr->batteryW > 6 + plr->level), -1, -1, 1);
|
damage = getDamage(damage.first, target->defense, true, (plr->batteryW > 6 + plr->level), -1, -1, 0);
|
||||||
|
|
||||||
if (plr->batteryW >= 6 + plr->level)
|
if (plr->batteryW >= 6 + plr->level)
|
||||||
plr->batteryW -= 6 + plr->level;
|
plr->batteryW -= 6 + plr->level;
|
||||||
@ -1188,6 +1194,9 @@ bool MobManager::aggroCheck(Mob *mob, time_t currTime) {
|
|||||||
mob->roamY = mob->appearanceData.iY;
|
mob->roamY = mob->appearanceData.iY;
|
||||||
mob->roamZ = mob->appearanceData.iZ;
|
mob->roamZ = mob->appearanceData.iZ;
|
||||||
|
|
||||||
|
if (mob->groupLeader != 0)
|
||||||
|
followToCombat(mob);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1380,3 +1389,39 @@ void MobManager::projectileHit(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
Bullets[plr->iID].erase(resp->iBulletID);
|
Bullets[plr->iID].erase(resp->iBulletID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MobManager::followToCombat(Mob *mob) {
|
||||||
|
if (Mobs.find(mob->groupLeader) != Mobs.end()) {
|
||||||
|
Mob* leadMob = Mobs[mob->groupLeader];
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (leadMob->groupMember[i] == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (Mobs.find(leadMob->groupMember[i]) == Mobs.end()) {
|
||||||
|
std::cout << "[WARN] roamingStep: leader can't find a group member!" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Mob* followerMob = Mobs[leadMob->groupMember[i]];
|
||||||
|
|
||||||
|
if (followerMob->state == MobState::COMBAT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
followerMob->target = mob->target;
|
||||||
|
followerMob->state = MobState::COMBAT;
|
||||||
|
followerMob->nextMovement = getTime();
|
||||||
|
followerMob->nextAttack = 0;
|
||||||
|
|
||||||
|
followerMob->roamX = followerMob->appearanceData.iX;
|
||||||
|
followerMob->roamY = followerMob->appearanceData.iY;
|
||||||
|
followerMob->roamZ = followerMob->appearanceData.iZ;
|
||||||
|
}
|
||||||
|
leadMob->target = mob->target;
|
||||||
|
leadMob->state = MobState::COMBAT;
|
||||||
|
leadMob->nextMovement = getTime();
|
||||||
|
leadMob->nextAttack = 0;
|
||||||
|
|
||||||
|
leadMob->roamX = leadMob->appearanceData.iX;
|
||||||
|
leadMob->roamY = leadMob->appearanceData.iY;
|
||||||
|
leadMob->roamZ = leadMob->appearanceData.iZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -163,4 +163,6 @@ namespace MobManager {
|
|||||||
/// returns bullet id
|
/// returns bullet id
|
||||||
int8_t addBullet(Player* plr, bool isGrenade);
|
int8_t addBullet(Player* plr, bool isGrenade);
|
||||||
|
|
||||||
|
void followToCombat(Mob *mob);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user