From ffcebec91192484588b2a5853782d026e5370f0c Mon Sep 17 00:00:00 2001 From: Lance Date: Fri, 26 May 2006 09:46:45 +0000 Subject: * Mob control engine tested 99% working so far. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@6770 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 1 + db/const.txt | 11 +++++ npc/sample/monster_controller.cpp | 33 ++++++++++++++ src/map/battle.c | 18 +++++++- src/map/clif.c | 4 +- src/map/mob.c | 79 +++++++++++++++++++--------------- src/map/mob.h | 1 + src/map/npc.c | 4 +- src/map/script.c | 90 ++++++++++++++++++++++++--------------- src/map/script.h | 2 +- 10 files changed, 167 insertions(+), 76 deletions(-) diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 2db105c3b..80314a053 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,6 +4,7 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. 2006/05/26 + * Mob control engine tested 99% working so far. [Lance] * Change scripting engine's NPC scope vars to dot (.) style. * Improved and (should be fully) fixed the mob control engine. [Lance] * Fixed typos in char.c [Lance] diff --git a/db/const.txt b/db/const.txt index 5b41f0376..07895eb30 100644 --- a/db/const.txt +++ b/db/const.txt @@ -698,6 +698,17 @@ MOB_RACE 19 MOB_ELEMENT 20 MOB_MODE 21 +AI_ACTION_TYPE 0 +AI_ACTION_TAR_TYPE 1 +AI_ACTION_TAR 2 +AI_ACTION_SRC 3 +AI_ACTION_TAR_TYPE_PC 1 +AI_ACTION_TAR_TYPE_MOB 2 +AI_ACTION_TAR_TYPE_PET 4 +AI_ACTION_TAR_TYPE_HOMUN 8 +AI_ACTION_TYPE_ATTACK 1 +AI_ACTION_TYPE_DETECT 2 + ALL_CLIENT 0 ALL_SAMEMAP 1 AREA 2 diff --git a/npc/sample/monster_controller.cpp b/npc/sample/monster_controller.cpp index 58b5693a8..479320f2f 100644 --- a/npc/sample/monster_controller.cpp +++ b/npc/sample/monster_controller.cpp @@ -44,6 +44,39 @@ prontera.gat,180,200,4 script Monster Controller 123,{ return; } + if(getarraysize(.ai_action) == 4){ + announce "[Mob Control] AI Action Received from " + .ai_action[AI_ACTION_SRC] + "!",bc_all; + switch(.ai_action[AI_ACTION_TAR_TYPE]){ + case AI_ACTION_TAR_TYPE_PC: + set .@action_from$, "Player"; + set .@action_name$, rid2name(.ai_action[AI_ACTION_TAR]); + break; + case AI_ACTION_TAR_TYPE_MOB: + set .@action_from$, "Monster"; + set .@action_name$, ""+.ai_action[AI_ACTION_TAR]; + break; + case AI_ACTION_TAR_TYPE_PET: + set .@action_from$, "Pet"; + set .@action_name$, ""+.ai_action[AI_ACTION_TAR]; + break; + case AI_ACTION_TAR_TYPE_HOMUN: + set .@action_from$, "Homunculus"; + set .@action_name$, ""+.ai_action[AI_ACTION_TAR]; + break; + default: + set .@action_from$, "Unknown"; + set .@action_name$, ""+.ai_action[AI_ACTION_TAR]; + break; + } + if(.ai_action[AI_ACTION_TYPE] == AI_ACTION_TYPE_ATTACK) + set .@action_type$, "attacked by"; + else + set .@action_type$, "detected"; + announce "Action " + .@action_type$ + " [" + .@action_from$ + "] " + .@action_name$ + "!", bc_all; + deletearray .ai_action, 4; + end; + } + L_MainMenu: mes "[Monster Controller]"; mes "Current active monsters:"; diff --git a/src/map/battle.c b/src/map/battle.c index a263d4874..9bbcce01e 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -3426,8 +3426,24 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f case BL_MOB: { TBL_MOB*md = (TBL_MOB*)s_bl; - if(md->state.killer) // Is on a rampage too :D + if(md->state.killer){ // Is on a rampage too :D + switch(t_bl->type){ + case BL_MOB: + if(md->master_id != 0 && ((TBL_MOB *)t_bl)->master_id == md->master_id) + state |= BCT_PARTY; + break; + case BL_PC: + if(t_bl->id == md->master_id) + state |= BCT_PARTY; + break; + case BL_PET: + if(((TBL_PET *)t_bl)->msd->bl.id == md->master_id) + state |= BCT_PARTY; + break; + } state |= BCT_ENEMY; + break; + } if (!agit_flag && md->guardian_data && md->guardian_data->guild_id) return 0; //Disable guardians/emperium owned by Guilds on non-woe times. if (!md->special_state.ai) { //Normal mobs. diff --git a/src/map/clif.c b/src/map/clif.c index c67321d3c..a4b7ea2f2 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -9386,8 +9386,8 @@ void clif_parse_NpcBuyListSend(int fd,struct map_session_data *sd) if((nd = ((struct npc_data *)map_id2bl(sd->npc_shopid))->master_nd)){ sprintf(npc_ev, "%s::OnBuyItem", nd->exname); for(i=0;ibl,bl,BCT_ENEMY)<=0 || !status_check_skilluse(&md->bl, bl, 0, 0)) + if ((*target) == bl || !status_check_skilluse(&md->bl, bl, 0, 0)) + return 0; + + if(md->nd){ + setd_sub(NULL, NULL, ".ai_action", 0, (void *)(int)2, &md->nd->u.scr.script->script_vars); + setd_sub(NULL, NULL, ".ai_action", 1, (void *)(int)bl->type, &md->nd->u.scr.script->script_vars); + setd_sub(NULL, NULL, ".ai_action", 2, (void *)bl->id, &md->nd->u.scr.script->script_vars); + setd_sub(NULL, NULL, ".ai_action", 3, (void *)md->bl.id, &md->nd->u.scr.script->script_vars); + run_script(md->nd->u.scr.script, 0, 0, md->nd->bl.id); + return 0; // We have script handling the work. + } + + if(battle_check_target(&md->bl,bl,BCT_ENEMY)<=0) return 0; switch (bl->type) @@ -906,9 +918,6 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick) return 0; } - if(bl->type == BL_MOB && ((TBL_MOB *)bl)->master_id && ((TBL_MOB *)bl)->master_id != md->master_id) // Just in case something screws up - md->master_id = ((TBL_MOB *)bl)->master_id; - if(status_get_mode(&md->bl)&MD_CANMOVE) { //If the mob can move, follow around. [Check by Skotlex] @@ -1320,7 +1329,7 @@ static int mob_ai_sub_lazy(DBKey key,void * data,va_list app) ap = va_arg(app, va_list); - if (battle_config.mob_ai&32 && map[md->bl.m].users>0) + if (md->nd || (battle_config.mob_ai&32 && map[md->bl.m].users>0)) return mob_ai_sub_hard(&md->bl, ap); tick=va_arg(ap,unsigned int); @@ -1494,39 +1503,49 @@ int mob_timer_delete(int tid, unsigned int tick, int id, int data) return 0; } -/*========================================== - * - *------------------------------------------ - */ -int mob_deleteslave_sub(struct block_list *bl,va_list ap) +int mob_convertslave_sub(struct block_list *bl,va_list ap) { - struct mob_data *md; - int id; + struct mob_data *md, *md2 = NULL; nullpo_retr(0, bl); nullpo_retr(0, ap); nullpo_retr(0, md = (struct mob_data *)bl); - id=va_arg(ap,int); - if(md->master_id > 0 && md->master_id == id ) - mob_damage(NULL,md,md->hp,1); + md2=va_arg(ap,TBL_MOB *); + + if(md->master_id > 0 && md->master_id == md2->bl.id){ + md->master_id = md2->master_id; + md->state.killer = md2->state.killer; + md->special_state.ai = md2->special_state.ai; + } + return 0; } -int mob_convertslave_sub(struct block_list *bl,va_list ap) +int mob_convertslave(struct mob_data *md) +{ + nullpo_retr(0, md); + + map_foreachinmap(mob_convertslave_sub, md->bl.m, BL_MOB, md); + return 0; +} + +/*========================================== + * + *------------------------------------------ + */ +int mob_deleteslave_sub(struct block_list *bl,va_list ap) { struct mob_data *md; - int id, master; + int id; nullpo_retr(0, bl); nullpo_retr(0, ap); nullpo_retr(0, md = (struct mob_data *)bl); id=va_arg(ap,int); - master=va_arg(ap,int); - if(md->master_id > 0 && md->master_id == id ) - md->master_id = master; + mob_damage(NULL,md,md->hp,1); return 0; } /*========================================== @@ -1540,14 +1559,6 @@ int mob_deleteslave(struct mob_data *md) map_foreachinmap(mob_deleteslave_sub, md->bl.m, BL_MOB,md->bl.id); return 0; } - -int mob_convertslave(struct mob_data *md) -{ - nullpo_retr(0, md); - - map_foreachinmap(mob_convertslave_sub, md->bl.m, BL_MOB,md->bl.id,md->master_id); - return 0; -} // Mob respawning through KAIZEL or NPC_REBIRTH [Skotlex] int mob_respawn(int tid, unsigned int tick, int id,int data ) { @@ -1592,7 +1603,6 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type) int ret, mode; int drop_rate; int race; - char buffer[64]; nullpo_retr(0, md); //srcはNULLで呼ばれる場合もあるので、他でチェック @@ -1601,12 +1611,11 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type) if(src){ if(md->nd){ - sprintf(buffer, "$@%d_attacker", md->bl.id); - set_var(NULL, buffer, (void *)src->id); - sprintf(buffer, "$@%d_attacktype", md->bl.id); - set_var(NULL, buffer, (void *)(int)src->type); - sprintf(buffer, "%s::OnDamage", md->nd->exname); - npc_event_do(buffer); + setd_sub(NULL, NULL, ".ai_action", 0, (void *)(int)1, &md->nd->u.scr.script->script_vars); + setd_sub(NULL, NULL, ".ai_action", 1, (void *)(int)src->type, &md->nd->u.scr.script->script_vars); + setd_sub(NULL, NULL, ".ai_action", 2, (void *)src->id, &md->nd->u.scr.script->script_vars); + setd_sub(NULL, NULL, ".ai_action", 3, (void *)md->bl.id, &md->nd->u.scr.script->script_vars); + run_script(md->nd->u.scr.script, 0, 0, md->nd->bl.id); } if(src->type == BL_PC) { sd = (struct map_session_data *)src; diff --git a/src/map/mob.h b/src/map/mob.h index 3eea67ec4..fcd0ac6f5 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -175,6 +175,7 @@ int mobskill_castend_id( int tid, unsigned int tick, int id,int data ); int mobskill_castend_pos( int tid, unsigned int tick, int id,int data ); int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id); int mob_countslave(struct block_list *bl); +int mob_convertslave(struct mob_data *md); int mob_is_clone(int class_); diff --git a/src/map/npc.c b/src/map/npc.c index 37e47585c..616042811 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -1268,8 +1268,8 @@ int npc_selllist(struct map_session_data *sd,int n,unsigned short *item_list) log_pick(sd, "S", 0, nameid, qty, &sd->status.inventory[idx]); if(nd) { - setd_sub(NULL,sd, "@sold_nameid", i, (void *)(int)sd->status.inventory[idx].nameid); - setd_sub(NULL,sd, "@sold_quantity", i, (void *)(int)qty); + setd_sub(NULL,sd, "@sold_nameid", i, (void *)(int)sd->status.inventory[idx].nameid,NULL); + setd_sub(NULL,sd, "@sold_quantity", i, (void *)(int)qty,NULL); } itemamount+=qty; pc_delitem(sd,idx,qty,0); diff --git a/src/map/script.c b/src/map/script.c index 88d4ef9e7..04f5532cc 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -9910,9 +9910,9 @@ int buildin_distance(struct script_state *st){ // <--- [zBuffer] List of mathematics commands // [zBuffer] List of dynamic var commands ---> -void setd_sub(struct script_state *st, struct map_session_data *sd, char *varname, int elem, void *value) +void setd_sub(struct script_state *st, struct map_session_data *sd, char *varname, int elem, void *value, struct linkdb_node **ref) { - set_reg(st, sd, add_str((unsigned char *) varname)+(elem<<24), varname, value,NULL); + set_reg(st, sd, add_str((unsigned char *) varname)+(elem<<24), varname, value, ref); return; } @@ -9932,9 +9932,9 @@ int buildin_setd(struct script_state *st) sd = script_rid2sd(st); if(varname[strlen(varname)-1] != '$') { - setd_sub(st,sd, varname, elem, (void *)atoi(value)); + setd_sub(st,sd, varname, elem, (void *)atoi(value),NULL); } else { - setd_sub(st,sd, varname, elem, (void *)value); + setd_sub(st,sd, varname, elem, (void *)value,NULL); } return 0; @@ -9963,12 +9963,12 @@ int buildin_query_sql(struct script_state *st) { if((sql_res = mysql_store_result(&mmysql_handle))){ if(name[strlen(name)-1] != '$') { while(i<128 && (sql_row = mysql_fetch_row(sql_res))){ - setd_sub(st,sd, name, i, (void *)atoi(sql_row[0])); + setd_sub(st,sd, name, i, (void *)atoi(sql_row[0]),NULL); i++; } } else { while(i<128 && (sql_row = mysql_fetch_row(sql_res))){ - setd_sub(st,sd, name, i, (void *)sql_row[0]); + setd_sub(st,sd, name, i, (void *)sql_row[0],NULL); i++; } } @@ -10298,13 +10298,13 @@ int buildin_rid2name(struct script_state *st){ if((bl = map_id2bl(rid))){ switch(bl->type){ case BL_MOB: - push_str(st->stack,C_STR,((struct mob_data *)bl)->name); + push_str(st->stack,C_CONSTSTR,((struct mob_data *)bl)->name); break; case BL_PC: - push_str(st->stack,C_STR,((struct map_session_data *)bl)->status.name); + push_str(st->stack,C_CONSTSTR,((struct map_session_data *)bl)->status.name); break; case BL_NPC: - push_str(st->stack,C_STR,((struct npc_data *)bl)->exname); + push_str(st->stack,C_CONSTSTR,((struct npc_data *)bl)->exname); break; default: ShowError("buildin_rid2name: BL type unknown.\n"); @@ -10508,30 +10508,31 @@ int buildin_getmobdata(struct script_state *st) { } else { num=st->stack->stack_data[st->start+3].u.num; name=(char *)(str_buf+str_data[num&0x00ffffff].str); - setd_sub(st,map_id2sd(st->rid),name,0,(void *)(int)md->class_); - setd_sub(st,map_id2sd(st->rid),name,1,(void *)(int)md->level); - setd_sub(st,map_id2sd(st->rid),name,2,(void *)(int)md->hp); - setd_sub(st,map_id2sd(st->rid),name,3,(void *)(int)md->max_hp); - setd_sub(st,map_id2sd(st->rid),name,4,(void *)(int)md->master_id); - setd_sub(st,map_id2sd(st->rid),name,5,(void *)(int)md->bl.m); - setd_sub(st,map_id2sd(st->rid),name,6,(void *)(int)md->bl.x); - setd_sub(st,map_id2sd(st->rid),name,7,(void *)(int)md->bl.y); - setd_sub(st,map_id2sd(st->rid),name,8,(void *)(int)md->speed); - setd_sub(st,map_id2sd(st->rid),name,9,(void *)(int)md->mode); - setd_sub(st,map_id2sd(st->rid),name,10,(void *)(int)md->special_state.ai); - setd_sub(st,map_id2sd(st->rid),name,11,(void *)(int)md->db->option); - setd_sub(st,map_id2sd(st->rid),name,12,(void *)(int)md->vd->sex); - setd_sub(st,map_id2sd(st->rid),name,13,(void *)(int)md->vd->class_); - setd_sub(st,map_id2sd(st->rid),name,14,(void *)(int)md->vd->hair_style); - setd_sub(st,map_id2sd(st->rid),name,15,(void *)(int)md->vd->hair_color); - setd_sub(st,map_id2sd(st->rid),name,16,(void *)(int)md->vd->head_bottom); - setd_sub(st,map_id2sd(st->rid),name,17,(void *)(int)md->vd->head_mid); - setd_sub(st,map_id2sd(st->rid),name,18,(void *)(int)md->vd->head_top); - setd_sub(st,map_id2sd(st->rid),name,19,(void *)(int)md->vd->cloth_color); - setd_sub(st,map_id2sd(st->rid),name,20,(void *)(int)md->vd->shield); - setd_sub(st,map_id2sd(st->rid),name,21,(void *)(int)md->vd->weapon); - setd_sub(st,map_id2sd(st->rid),name,22,(void *)(int)md->vd->shield); - setd_sub(st,map_id2sd(st->rid),name,23,(void *)(int)md->ud.dir); + setd_sub(st,map_id2sd(st->rid),name,0,(void *)(int)md->class_,NULL); + setd_sub(st,map_id2sd(st->rid),name,1,(void *)(int)md->level,NULL); + setd_sub(st,map_id2sd(st->rid),name,2,(void *)(int)md->hp,NULL); + setd_sub(st,map_id2sd(st->rid),name,3,(void *)(int)md->max_hp,NULL); + setd_sub(st,map_id2sd(st->rid),name,4,(void *)(int)md->master_id,NULL); + setd_sub(st,map_id2sd(st->rid),name,5,(void *)(int)md->bl.m,NULL); + setd_sub(st,map_id2sd(st->rid),name,6,(void *)(int)md->bl.x,NULL); + setd_sub(st,map_id2sd(st->rid),name,7,(void *)(int)md->bl.y,NULL); + setd_sub(st,map_id2sd(st->rid),name,8,(void *)(int)md->speed,NULL); + setd_sub(st,map_id2sd(st->rid),name,9,(void *)(int)md->mode,NULL); + setd_sub(st,map_id2sd(st->rid),name,10,(void *)(int)md->special_state.ai,NULL); + setd_sub(st,map_id2sd(st->rid),name,11,(void *)(int)md->db->option,NULL); + setd_sub(st,map_id2sd(st->rid),name,12,(void *)(int)md->vd->sex,NULL); + setd_sub(st,map_id2sd(st->rid),name,13,(void *)(int)md->vd->class_,NULL); + setd_sub(st,map_id2sd(st->rid),name,14,(void *)(int)md->vd->hair_style,NULL); + setd_sub(st,map_id2sd(st->rid),name,15,(void *)(int)md->vd->hair_color,NULL); + setd_sub(st,map_id2sd(st->rid),name,16,(void *)(int)md->vd->head_bottom,NULL); + setd_sub(st,map_id2sd(st->rid),name,17,(void *)(int)md->vd->head_mid,NULL); + setd_sub(st,map_id2sd(st->rid),name,18,(void *)(int)md->vd->head_top,NULL); + setd_sub(st,map_id2sd(st->rid),name,19,(void *)(int)md->vd->cloth_color,NULL); + setd_sub(st,map_id2sd(st->rid),name,20,(void *)(int)md->vd->shield,NULL); + setd_sub(st,map_id2sd(st->rid),name,21,(void *)(int)md->vd->weapon,NULL); + setd_sub(st,map_id2sd(st->rid),name,22,(void *)(int)md->vd->shield,NULL); + setd_sub(st,map_id2sd(st->rid),name,23,(void *)(int)md->ud.dir,NULL); + setd_sub(st,map_id2sd(st->rid),name,24,(void *)(int)md->state.killer,NULL); } return 0; } @@ -10617,6 +10618,9 @@ int buildin_setmobdata(struct script_state *st){ case 23: md->ud.dir = (unsigned char)value; break; + case 24: + md->state.killer = value>0?1:0; + break; default: ShowError("buildin_setmobdata: argument id is not identified."); break; @@ -10647,6 +10651,7 @@ int buildin_mobattack(struct script_state *st) { if((md = (struct mob_data *)map_id2bl(id))){ if (md && md->bl.type == BL_MOB) { md->state.killer = 1; + md->special_state.ai = 1; if(bl){ md->target_id = bl->id; unit_walktobl(&md->bl, bl, 65025, 2); @@ -10698,6 +10703,8 @@ int buildin_mobassist(struct script_state *st) { if(md && md->bl.type == BL_MOB) { ud = unit_bl2ud(bl); md->master_id = bl->id; + md->state.killer = 1; + mob_convertslave(md); if (ud) { if (ud->target) md->target_id = ud->target; @@ -10746,9 +10753,22 @@ int buildin_mobemote(struct script_state *st) { int buildin_mobattach(struct script_state *st){ int id; struct mob_data *md = NULL; + struct npc_data *nd = NULL; + char *npcname = NULL; id = conv_num(st, & (st->stack->stack_data[st->start+2])); - if((md = (struct mob_data *)map_id2bl(id)) && md->bl.type == BL_MOB) - md->nd = (struct npc_data *)map_id2bl(st->oid); + if(st->end > st->start + 3){ + npcname = conv_str(st, & (st->stack->stack_data[st->start+3])); + } + + if(npcname) + nd = npc_name2id(npcname); + else + nd = (struct npc_data *)map_id2bl(st->oid); + + if(nd) + if((md = (struct mob_data *)map_id2bl(id)) && md->bl.type == BL_MOB) + md->nd = nd; + return 0; } diff --git a/src/map/script.h b/src/map/script.h index 87b03a5af..47de38c5c 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -69,7 +69,7 @@ int run_script(struct script_code *rootscript,int pos,int rid,int oid); int set_var(struct map_session_data *sd, char *name, void *val); int conv_num(struct script_state *st,struct script_data *data); char* conv_str(struct script_state *st,struct script_data *data); -void setd_sub(struct script_state *st, struct map_session_data *sd, char *varname, int elem, void *value); +void setd_sub(struct script_state *st, struct map_session_data *sd, char *varname, int elem, void *value, struct linkdb_node **ref); int run_script_timer(int tid, unsigned int tick, int id, int data); int run_script_main(struct script_state *st); -- cgit v1.2.3-70-g09d2