Wave mode instances - walkthrough conversions (#3884)
* Wave mode instances - walkthrough conversions * NPC_EMOTION and NPC_EMOTION_ON disrupted the walking system and have been restricted on the maps. * Implemented AI_SPECIALs. AI and normal monsters can naturally fight each others. However monsters with AI_SPECIAL can't be hit by normal monsters. * Implemented mob_setidleevent command. `mob_setidleevent <GID>,<event>;` This command will attach an event label to the monster with the given <GID> which will execute when the <GID> is idle. * Added parameters to unitskilluseid and unitskillusepos -- `<cancel>`: define if the skill can be interrupted when hit (by default the cancel value was 'castcancel' from skill_db.txt) -- `<Line_ID>` : the monster will say the message from 'Line_ID' in mob_chat_db.yml when casting the skill * Added `UMOB_IGNORE_CELL_STACK_LIMIT` for setunitdata/getunitdata script command. When true, the monster will ignore the stack limit (max number of characters that can stack within a single cell) defined by 'official_cell_stack_limit' in misc.conf * The script is disabled by default like on KRO Thanks to @Lemongrass3110 @aleos89 @Badarosk0 @sigtus @Questune09 !
This commit is contained in:
@@ -1516,6 +1516,10 @@ int mob_unlocktarget(struct mob_data *md, t_tick tick)
|
||||
//Because it is not unset when the mob finishes walking.
|
||||
md->state.skillstate = MSS_IDLE;
|
||||
case MSS_IDLE:
|
||||
if( md->ud.walktimer == INVALID_TIMER && md->idle_event[0] && npc_event_do_id( md->idle_event, md->bl.id ) > 0 ){
|
||||
md->idle_event[0] = 0;
|
||||
break;
|
||||
}
|
||||
// Idle skill.
|
||||
if (!(++md->ud.walk_count%IDLE_SKILL_INTERVAL) && mobskill_use(md, tick, -1))
|
||||
break;
|
||||
@@ -1543,7 +1547,8 @@ int mob_unlocktarget(struct mob_data *md, t_tick tick)
|
||||
md->ud.target_to = 0;
|
||||
unit_set_target(&md->ud, 0);
|
||||
}
|
||||
if (battle_config.official_cell_stack_limit > 0
|
||||
|
||||
if (!md->ud.state.ignore_cell_stack_limit && battle_config.official_cell_stack_limit > 0
|
||||
&& (md->min_chase == md->db->range3 || battle_config.mob_ai & 0x8)
|
||||
&& map_count_oncell(md->bl.m, md->bl.x, md->bl.y, BL_CHAR | BL_NPC, 1) > battle_config.official_cell_stack_limit) {
|
||||
unit_walktoxy(&md->bl, md->bl.x, md->bl.y, 8);
|
||||
@@ -2045,6 +2050,15 @@ static int mob_ai_sub_lazy(struct mob_data *md, va_list args)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (md->ud.walktimer == INVALID_TIMER) {
|
||||
// Because it is not unset when the mob finishes walking.
|
||||
md->state.skillstate = MSS_IDLE;
|
||||
if (md->idle_event[0] && npc_event_do_id( md->idle_event, md->bl.id ) > 0) {
|
||||
md->idle_event[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( DIFF_TICK(md->next_walktime,tick) < 0 && status_has_mode(&md->status,MD_CANMOVE) && unit_can_move(&md->bl) )
|
||||
{
|
||||
// Move probability for mobs away from players
|
||||
@@ -2056,9 +2070,6 @@ static int mob_ai_sub_lazy(struct mob_data *md, va_list args)
|
||||
}
|
||||
else if( md->ud.walktimer == INVALID_TIMER )
|
||||
{
|
||||
//Because it is not unset when the mob finishes walking.
|
||||
md->state.skillstate = MSS_IDLE;
|
||||
|
||||
// Probability for mobs far from players from doing their IDLE skill.
|
||||
// In Aegis, this is 100% for mobs that have been activated by players and none otherwise.
|
||||
if( mob_is_spotted(md) &&
|
||||
@@ -3657,6 +3668,24 @@ struct mob_data *mob_getfriendstatus(struct mob_data *md,int cond1,int cond2)
|
||||
return fr;
|
||||
}
|
||||
|
||||
// Display message from mob_chat_db.yml
|
||||
bool mob_chat_display_message(mob_data &md, uint16 msg_id) {
|
||||
std::shared_ptr<s_mob_chat> mc = mob_chat_db.find(msg_id);
|
||||
|
||||
if (mc != nullptr) {
|
||||
std::string name = md.name, output;
|
||||
std::size_t unique = name.find("#");
|
||||
|
||||
if (unique != std::string::npos)
|
||||
name = name.substr(0, unique); // discard extra name identifier if present [Daegaladh]
|
||||
output = name + " : " + mc->msg;
|
||||
|
||||
clif_messagecolor(&md.bl, mc->color, output.c_str(), true, AREA_CHAT_WOC);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* Skill use judging
|
||||
*------------------------------------------*/
|
||||
@@ -3856,18 +3885,7 @@ int mobskill_use(struct mob_data *md, t_tick tick, int event)
|
||||
}
|
||||
//Skill used. Post-setups...
|
||||
if ( ms[i]->msg_id ){ //Display color message [SnakeDrak]
|
||||
std::shared_ptr<s_mob_chat> mc = mob_chat_db.find(ms[i]->msg_id);
|
||||
|
||||
if (mc) {
|
||||
std::string name = md->name, output;
|
||||
std::size_t unique = name.find("#");
|
||||
|
||||
if (unique != std::string::npos)
|
||||
name = name.substr(0, unique); // discard extra name identifier if present [Daegaladh]
|
||||
output = name + " : " + mc->msg;
|
||||
|
||||
clif_messagecolor(&md->bl, mc->color, output.c_str(), true, AREA_CHAT_WOC);
|
||||
}
|
||||
mob_chat_display_message(*md, ms[i]->msg_id);
|
||||
}
|
||||
if(!(battle_config.mob_ai&0x200)) { //pass on delay to same skill.
|
||||
for (j = 0; j < ms.size(); j++)
|
||||
@@ -4446,7 +4464,7 @@ uint64 MobDatabase::parseBodyNode(const YAML::Node &node) {
|
||||
mob->status.rhw.atk2 = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
if (this->nodeExists(node, "Defense")) {
|
||||
uint16 def;
|
||||
|
||||
@@ -4463,7 +4481,7 @@ uint64 MobDatabase::parseBodyNode(const YAML::Node &node) {
|
||||
if (!exists)
|
||||
mob->status.def = 0;
|
||||
}
|
||||
|
||||
|
||||
if (this->nodeExists(node, "MagicDefense")) {
|
||||
uint16 def;
|
||||
|
||||
@@ -4480,7 +4498,7 @@ uint64 MobDatabase::parseBodyNode(const YAML::Node &node) {
|
||||
if (!exists)
|
||||
mob->status.mdef = 0;
|
||||
}
|
||||
|
||||
|
||||
if (this->nodeExists(node, "Str")) {
|
||||
uint16 stat;
|
||||
|
||||
@@ -4552,7 +4570,7 @@ uint64 MobDatabase::parseBodyNode(const YAML::Node &node) {
|
||||
if (!exists)
|
||||
mob->status.luk = 1;
|
||||
}
|
||||
|
||||
|
||||
if (this->nodeExists(node, "AttackRange")) {
|
||||
uint16 range;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user