Removed the mob controller system, now a customization (see topic:194375).

The system consists of
 * script command to spawn a controlled mob
 * script commands to attach npcs to such mobs and manipulate their AI
 * a page of documentation for these commands
 * callbacks at various source code locations that invoke the attached npcs
 * two npc examples

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@13021 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
ultramage 2008-07-31 05:37:40 +00:00
parent 02995dceab
commit 115c5b6896
14 changed files with 7 additions and 762 deletions

View File

@ -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.
2008/07/31
* Removed the mob controller system, now a customization (see topic:194375) [ultramage]
* Fixed: commented out loginlog in convert engine sql tables (loginlog table is in logs database now) [akrus]
2008/07/30
* Fixed TXT storage code handling storage incorrectly (bugreport:1928)

View File

@ -4727,78 +4727,6 @@ To evolve a homunculus, the invoking player must have a homunculus,
the homunculus must not be the last evolution and
the homunculus must be on at least 91000/100000 intimacy with it's owner.
---------------------------------------
------------------------------------------------
//===========================================\\
|| Mob Control Suit Commands ||
\\===========================================//
------------------------------------------------
---------------------------------------
* mobspawn (<monster name>,<monster ID>,<mapname>,<x>,<y>)
* mobRemove <GID>;
This is used to spawn a monster and return it's Game ID, to be used
in the unit/mobcontrol commands.
Note, I will use the stuff here in the examples for the unitcontrol.
Example(s):
//Spawns a poring named poi poi and put's it's GID in .GID.
set .GID,mobspawn("Poi Poi",1002,"prontera",160,180);
//would kill our poring.
mobRemove .GID;
---------------------------------------
* getmobdata (<GID>,<arrayname>)
* setmobdata <GID>,<parameter>,<new value>;
This is used to get and set special data related to the monster.
With getmobdata, the array given will be filled with the current data. In setmobdata
the indexes in the array would be used to set that data on the monster.
Parameters (indexes) are:
0 = class (big, small, normal) 7 = y 14 = hair style 21 = weapon
1 = level 8 = speed 15 = hair color 22 = shield (again)
2 = HP 9 = mode (see doc/mob_db_mode_list.txt) 16 = head gear bottom 23 = looking dir
3 = max HP 10 = special AI state (?) 17 = head gear middle 24 = killer state (1 or 0)
4 = master ID (aid of the master, summon) 11 = SC option 18 = head gear top 25 = callback flag
5 = map index 12 = sex 19 = cloth color 26 = no random walk (1 or 0)
6 = x 13 = class (Monster ID, Job ID) 20 = shield
Example(s):
//this will set all the mobdata in the @array variable. (@array[1] being level, @array[13] class etc)
getmobdata .GID,@array;
//set the max hp of our poring to 1000.
setmobdata .GID,3,1000;
---------------------------------------
* mobassist <GID>,<target id>;
This will make the monster assist the Target ID as if it was a summon of it.
Example(s):
/this will make our poring assist the current attached player! >:3
mobassist .GID,getcharid(3);
---------------------------------------
* mobattach <GID>{,"<NPC Name>"};
GID is the GID of a monster, NPC or account id. The NPC running or
he NPC name given is used to attach the monster.
By attaching a monster, the NPC to which it is attached is ran on special actions by the monster.
The system will set specific data in the .ai_action variable array on the NPC invoked.
The special AI actions types are set in the .ai_action at place AI_ACTION_TAR_TYPE
More AI_ vars are set in const.txt, and you can also look at sample/monstercontroller.cpp:
---------------------------------------
* unitwalk <GID>,<x>,<y>;
@ -4833,13 +4761,6 @@ For the emotions, you can look in db/const.txt for prefixes with e_
---------------------------------------
------------------------------------------------
//===========================================\\
|| End of Mob Control Suit Commands ||
\\===========================================//
------------------------------------------------
---------------------------------------
*disablenpc "<NPC object name>";
*enablenpc "<NPC object name>";

View File

@ -1,135 +0,0 @@
//(=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)
//( (c)2006 eAthena Development Team presents )
//( ______ __ __ )
//( /\ _ \/\ \__/\ \ v 1.00.00 )
//( __\ \ \_\ \ \ ,_\ \ \___ __ ___ __ )
//( /'__`\ \ __ \ \ \/\ \ _ `\ /'__`\/' _ `\ /'__`\ )
//( /\ __/\ \ \/\ \ \ \_\ \ \ \ \/\ __//\ \/\ \/\ \_\.\_ )
//( \ \____\\ \_\ \_\ \__\\ \_\ \_\ \____\ \_\ \_\ \__/.\_\ )
//( \/____/ \/_/\/_/\/__/ \/_/\/_/\/____/\/_/\/_/\/__/\/_/ )
//( _ _ _ _ _ _ _ _ _ _ _ _ _ )
//( / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ )
//( ( e | A | t | h | e | n | a ) ( S | c | r | i | p | t ) )
//( \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ )
//( )
//(=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)
// Programmed by [Lance] ver. 1.1
// ---------------------------------------------------------
// [ Sentry System ]
// - Guards main towns against aggresive monsters and bad
// players.
// [ Customization ]
// - See OnInit:
// =========================================================
- script sentry_system -1,{
function spawn_guardian {
set .mob_id[getarg(0)], mobspawn("Guardian Sentry",1904,.mob_map$[getarg(0)],.mob_x[getarg(0)],.mob_y[getarg(0)]);
mobattach .mob_id[getarg(0)]; // Attach events to this script.
setmobdata .mob_id[getarg(0)], 24, 1; // Enable killer mode.
setmobdata .mob_id[getarg(0)], 25,
AI_ACTION_TYPE_DETECT|
AI_ACTION_TYPE_KILL|
AI_ACTION_TYPE_UNLOCK|
AI_ACTION_TYPE_DEAD|
AI_ACTION_TYPE_ATTACK; // Define engine callback routines.
setmobdata .mob_id[getarg(0)], 26, 1; // Prevents random walking.
setmobdata .mob_id[getarg(0)], 10, 1; // Enable AI mode 1.
getmobdata .mob_id[getarg(0)], .@temp;
set .@temp[9], .@temp[9]^(0x400&.@temp[9]); // Check and remove MD_CHANGECHASE mode flag.
setmobdata .mob_id[getarg(0)], 9, .@temp[9];
return;
}
function search_entry {
set .@tmp, getarraysize(getarg(0));
for(set .@i, 0; .@i < .@tmp; set .@i, .@i + 1){
if(getelementofarray(getarg(0),.@i) == getarg(1))
break;
}
if(.@i == .@tmp)
return -1;
else
return .@i;
}
// Script Entry Point - When an event from the script engine is received.
if(getarraysize(.ai_action) == 4){ // Checks if the data is formatted correctly.
set .@tmp, search_entry(.mob_id, .ai_action[AI_ACTION_SRC]);
switch(.ai_action[AI_ACTION_TYPE]){
case AI_ACTION_TYPE_DETECT: // We see something...
if(.ai_busy[.@tmp] == 0){ // Not busy
switch(.ai_action[AI_ACTION_TAR_TYPE]){ // Check what have we here.
case AI_ACTION_TAR_TYPE_PC: // It's a player
if(Karma > .karma){ // pkarma is higher?
unittalk .ai_action[AI_ACTION_SRC], "Who goes there!";
unitemote .ai_action[AI_ACTION_SRC], e_gasp; // !
unitattack .ai_action[AI_ACTION_SRC],.ai_action[AI_ACTION_TAR];
// We're currently busy.
set .ai_busy[.@tmp], .ai_action[AI_ACTION_TAR];
}
break;
case AI_ACTION_TAR_TYPE_MOB: // It's a monster
if(.ai_action[AI_ACTION_TAR] != .ai_action[AI_ACTION_SRC]){
getmobdata .ai_action[AI_ACTION_TAR], .@temp;
if(.@temp[9]&0x804){ // In Aggressive mode?
unittalk .ai_action[AI_ACTION_SRC], "Protect the villagers we must!";
unitemote .ai_action[AI_ACTION_SRC], e_gasp; // !
unitattack .ai_action[AI_ACTION_SRC],.ai_action[AI_ACTION_TAR];
// We're currently busy.
set .ai_busy[.@tmp], .ai_action[AI_ACTION_TAR];
}
}
break;
}
}
break;
case AI_ACTION_TYPE_KILL: // We eliminated the criminal
if(.ai_action[AI_ACTION_TAR_TYPE] == AI_ACTION_TAR_TYPE_PC)
set Karma, 0;
case AI_ACTION_TYPE_UNLOCK: // Target lost :(
if(.@tmp != -1){
set .ai_busy[.@tmp], 0; // Remove him, we're free.
}
// Walk back to where we came from.
unitwalk .ai_action[AI_ACTION_SRC],.mob_x[.@tmp],.mob_y[.@tmp];
break;
case AI_ACTION_TYPE_DEAD: // We got killed :(
if(.ai_action[AI_ACTION_TAR_TYPE] == AI_ACTION_TAR_TYPE_PC){ // Attacker is a player?
if(Karma < 250)
set Karma, Karma + 5;
else
set Karma, 255;
}
sleep 10000; // 10 seconds until reinforcements arrive
spawn_guardian .@tmp;
break;
case AI_ACTION_TYPE_ATTACK: // Someone attacked us
if(.ai_action[AI_ACTION_TAR_TYPE] == AI_ACTION_TAR_TYPE_PC){ // Attacker is a player?
if(Karma < 250)
set Karma, Karma + 1;
else
set Karma, 255;
}
// The system's AI will auto attack any attackers. So we leave it here.
break;
}
}
deletearray .ai_action, getarraysize(.ai_action); // Cleans up and frees up memory
end;
OnInit:
// Customization ---------------------------------------------------------------------
setarray .mob_map$, "prt_fild08", "prt_fild05", "prt_fild06", "prt_gld";
setarray .mob_x,176,369,29,165;
setarray .mob_y,372,201,187,37;
set .karma, 5;
// -----------------------------------------------------------------------------------
set .@tmp, getarraysize(.mob_map$);
for(set .@i, 0; .@i < .@tmp; set .@i, .@i + 1){
spawn_guardian .@i;
}
debugmes "[Sentry System] Spawned " + .@i + " guardians.";
end;
}

View File

@ -1,198 +0,0 @@
// Variables Logging:
// .mc_moblist[] - ID list of mobs
prontera,180,200,4 script Monster Controller 123,{
function display_info {
getmobdata getarg(0), .@mob_data;
set .@array_size, getarraysize(.@mob_data);
for(set .@i, 0; .@i < .@array_size; set .@i, .@i + 1){
mes .@i + " - " + .@mob_data[.@i];
}
return;
}
function remove_mob {
mobremove getarg(0);
set .@mob_size, getarraysize(.mc_moblist);
for(set .@i, 0; .@i < .@mob_size; set .@i, .@i + 1){
if(.mc_moblist[.@i] == getarg(0))
deletearray .mc_moblist[.@i], 1;
}
}
function make_menu {
set .@array_size, getarraysize(.mc_moblist);
set .@tmp_str$, "";
for(set .@i, 0; .@i < .@array_size; set .@i, .@i + 1){
set .@tmp_str$, .@tmp_str$ + .mc_moblist[.@i] + ":";
}
select .@tmp_str$;
return .mc_moblist[@menu-1];
}
function summon_mob {
set .@mob_size, getarraysize(.mc_moblist);
set .mc_moblist[.@mob_size], mobspawn("Slave - " + .@mob_size, getarg(0), "prontera", 180, 200);
mobattach .mc_moblist[.@mob_size];
setmobdata .mc_moblist[.@mob_size], 25,
AI_ACTION_TYPE_ATTACK|
AI_ACTION_TYPE_DETECT|
AI_ACTION_TYPE_DEAD|
AI_ACTION_TYPE_ASSIST|
AI_ACTION_TYPE_KILL|
AI_ACTION_TYPE_UNLOCK|
AI_ACTION_TYPE_WALKACK|
AI_ACTION_TYPE_WARPACK;
return;
}
function list_mobs {
set .@mob_size, getarraysize(.mc_moblist);
for(set .@i, 0; .@i < .@mob_size; set .@i, .@i + 1){
mes "- " + .mc_moblist[.@i];
}
return;
}
if(getarraysize(.ai_action) == 4){
mapannounce "prontera", "[Mob Control] AI Action Received from " + .ai_action[AI_ACTION_SRC] + "!",16;
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$, rid2name(.ai_action[AI_ACTION_TAR]);
break;
case AI_ACTION_TAR_TYPE_PET:
set .@action_from$, "Pet";
set .@action_name$, rid2name(.ai_action[AI_ACTION_TAR]);
break;
case AI_ACTION_TAR_TYPE_HOMUN:
set .@action_from$, "Homunculus";
set .@action_name$, rid2name(.ai_action[AI_ACTION_TAR]);
break;
default:
set .@action_from$, "Unknown";
set .@action_name$, ""+.ai_action[AI_ACTION_TAR];
break;
}
switch(.ai_action[AI_ACTION_TYPE]){
case AI_ACTION_TYPE_ATTACK:
set .@action_type$, "Attacked by";
break;
case AI_ACTION_TYPE_DETECT:
set .@action_type$, "Detected";
break;
case AI_ACTION_TYPE_DEAD:
set .@action_type$, "Killed by";
remove_mob .ai_action[AI_ACTION_SRC];
break;
case AI_ACTION_TYPE_ASSIST:
set .@action_type$, "Assisting";
break;
case AI_ACTION_TYPE_UNLOCK:
set .@action_type$, "Unlocked target";
break;
case AI_ACTION_TYPE_KILL:
set .@action_type$, "Killed";
break;
case AI_ACTION_TYPE_WALKACK:
set .@action_type$, "Completed Walking";
break;
case AI_ACTION_TYPE_WARPACK:
set .@action_type$, "Warped";
break;
}
mapannounce "prontera", "Details - " + .@action_type$ + " [" + .@action_from$ + "] " + .@action_name$ + "!", 16;
deletearray .ai_action, 4;
end;
}
L_MainMenu:
mes "[Monster Controller]";
mes "Current active monsters:";
list_mobs;
switch(select("Summon","Remove","Information","Actions")){
case 1: // Summon
next;
mes "[Monster Controller]";
mes "Monster ID -";
input @mob_id;
next;
summon_mob @mob_id;
goto L_MainMenu;
break;
case 2: // Remove
remove_mob make_menu();
next;
goto L_MainMenu;
break;
case 3: // Information
set .@tmp, make_menu();
next;
mes "[Monster Info]";
display_info .@tmp;
next;
goto L_MainMenu;
break;
case 4: // Actions
goto L_AttackMenu;
break;
}
L_AttackMenu:
switch(select("Walk","Follow","Attack","Stop","Defend","Talk","Emote","Random Walk","Callback","Back")){
case 1: // Walk
set .@src, make_menu();
input .@x;
input .@y;
unitwalk .@src,.@x,.@y; // Mode 1: Walk to location.
break;
case 2: // Follow
set .@src, make_menu();
input .@tar;
unitwalk .@src, .@tar; // Mode 2: Walk to target.
break;
case 3: // Attack
set .@src, make_menu();
input .@tar;
unitattack .@src, .@tar;
break;
case 4: // Stop
set .@src, make_menu();
unitstop .@src;
break;
case 5: // Defend/Assist
set .@src, make_menu();
input .@tar;
mobassist .@src, .@tar;
break;
case 6: // Talk
set .@src, make_menu();
input .@text$;
unittalk .@src, .@text$;
break;
case 7: // Emote
set .@src, make_menu();
input .@emote;
unitemote .@src, .@emote;
break;
case 8:
set .@src, make_menu();
input .@flag;
setmobdata .@src, 26, .@flag;
break;
case 9:
set .@src, make_menu();
input .@flag;
setmobdata .@src, 25, .@flag;
break;
case 10:
next;
goto L_MainMenu;
}
goto L_AttackMenu;
}

View File

@ -79,7 +79,6 @@
//npc: npc/custom/Lance/FR_WeatherController.c
//npc: npc/custom/Lance/FR_MailSystem.c
//npc: npc/sample/npc_dynamic_shop.txt
//npc: npc/custom/Lance/Sentry.cpp
// --------------------------------------------------------------
// --------------------------------------------------------------

View File

@ -3209,9 +3209,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
TBL_MOB*md = (TBL_MOB*)s_bl;
if (!(agit_flag && map[m].flag.gvg_castle) && md->guardian_data && md->guardian_data->guild_id)
return 0; //Disable guardians/emperium owned by Guilds on non-woe times.
if(md->state.killer/* || !(battle_config.mob_ai&0x400)*/)
state |= BCT_ENEMY; //By default everyone hates mobs.
else
{ //Smart enemy criteria.
if (!md->special_state.ai) { //Normal mobs.
if (t_bl->type == BL_MOB && !((TBL_MOB*)t_bl)->special_state.ai)

View File

@ -8200,9 +8200,8 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
WFIFOSET(fd, WFIFOW(fd,2));
#ifdef PCRE_SUPPORT
// trigger listening mobs/npcs
// trigger listening npcs
map_foreachinrange(npc_chat_sub, &sd->bl, AREA_SIZE, BL_NPC, text, textlen, &sd->bl);
map_foreachinrange(mob_chat_sub, &sd->bl, AREA_SIZE, BL_MOB, text, textlen, &sd->bl);
#endif
// check for special supernovice phrase
@ -8841,8 +8840,7 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd)
if (!bl) return;
switch (bl->type) {
case BL_MOB:
if (!((TBL_MOB *)bl)->nd || !mob_script_callback((TBL_MOB *)bl, &sd->bl, CALLBACK_NPCCLICK))
clif_parse_ActionRequest_sub(sd, 0x07, bl->id, gettick());
clif_parse_ActionRequest_sub(sd, 0x07, bl->id, gettick());
break;
case BL_PC:
clif_parse_ActionRequest_sub(sd, 0x07, bl->id, gettick());

View File

@ -1114,9 +1114,6 @@ static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
if(battle_check_target(&md->bl,bl,BCT_ENEMY)<=0)
return 0;
if(md->nd && mob_script_callback(md, bl, CALLBACK_DETECT))
return 1; // We have script handling the work.
switch (bl->type)
{
case BL_PC:
@ -1298,8 +1295,6 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
tbl = NULL;
}
if (tbl && status_check_skilluse(&md->bl, tbl, 0, 0)) {
if(md->nd)
mob_script_callback(md, bl, CALLBACK_ASSIST);
md->target_id=tbl->id;
md->min_chase=md->db->range3+distance_bl(&md->bl, tbl);
if(md->min_chase>MAX_MINCHASE)
@ -1321,9 +1316,6 @@ int mob_unlocktarget(struct mob_data *md, unsigned int tick)
{
nullpo_retr(0, md);
if(md->nd)
mob_script_callback(md, map_id2bl(md->target_id), CALLBACK_UNLOCK);
switch (md->state.skillstate) {
case MSS_WALK:
if (md->ud.walktimer != -1)
@ -1368,7 +1360,6 @@ int mob_randomwalk(struct mob_data *md,unsigned int tick)
nullpo_retr(0, md);
if(DIFF_TICK(md->next_walktime,tick)>0 ||
md->state.no_random_walk ||
!unit_can_move(&md->bl) ||
!(status_get_mode(&md->bl)&MD_CANMOVE))
return 0;
@ -1717,7 +1708,7 @@ static int mob_ai_sub_lazy(struct mob_data *md, va_list args)
tick = va_arg(args,unsigned int);
if (md->nd || (battle_config.mob_ai&0x20 && map[md->bl.m].users>0))
if (battle_config.mob_ai&0x20 && map[md->bl.m].users>0)
return (int)mob_ai_sub_hard(md, tick);
if (md->bl.prev==NULL || md->status.hp == 0)
@ -1908,34 +1899,6 @@ int mob_timer_delete(int tid, unsigned int tick, int id, intptr data)
return 0;
}
int mob_convertslave_sub(struct block_list *bl,va_list ap)
{
struct mob_data *md, *md2 = NULL;
nullpo_retr(0, bl);
nullpo_retr(0, ap);
nullpo_retr(0, md = (struct mob_data *)bl);
md2=va_arg(ap,TBL_MOB *);
if(md->master_id > 0 && md->master_id == md2->bl.id){
md->state.killer = md2->state.killer;
md->special_state.ai = md2->special_state.ai;
md->nd = md2->nd;
md->callback_flag = md2->callback_flag;
}
return 0;
}
int mob_convertslave(struct mob_data *md)
{
nullpo_retr(0, md);
map_foreachinmap(mob_convertslave_sub, md->bl.m, BL_MOB, md);
return 0;
}
/*==========================================
*
*------------------------------------------*/
@ -2092,9 +2055,6 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage)
if (!src)
return;
if(md->nd)
mob_script_callback(md, src, CALLBACK_ATTACK);
if(md->special_state.ai==2/* && md->master_id == src->id*/)
{ //LOne WOlf explained that ANYONE can trigger the marine countdown skill. [Skotlex]
md->state.alchemist = 1;
@ -2533,15 +2493,6 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
//Emperium destroyed by script. Discard mvp character. [Skotlex]
mvp_sd = NULL;
if(src && src->type == BL_MOB){
struct mob_data *smd = (struct mob_data *)src;
if(smd->nd)
mob_script_callback(smd, &md->bl, CALLBACK_KILL);
}
if(md->nd)
mob_script_callback(md, src, CALLBACK_DEAD);
else
if(md->npc_event[0] && !md->state.npc_killmonster)
{
md->status.hp = 0; //So that npc_event invoked functions KNOW that I am dead.
@ -2584,11 +2535,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
if(pcdb_checkid(md->vd->class_))
{ //Player mobs are not removed automatically by the client.
if(md->nd){
md->vd->dead_sit = 1;
return 1; // Let the dead body stay there.. we have something to do with it :D
} else
clif_clearunit_delayed(&md->bl, tick+3000);
clif_clearunit_delayed(&md->bl, tick+3000);
}
if(!md->spawn) //Tell status_damage to remove it from memory.
@ -2608,10 +2555,7 @@ void mob_revive(struct mob_data *md, unsigned int hp)
md->last_pcneartime = 0;
if (!md->bl.prev)
map_addblock(&md->bl);
if(pcdb_checkid(md->vd->class_) && md->nd)
md->vd->dead_sit = 0;
else
clif_spawn(&md->bl);
clif_spawn(&md->bl);
skill_unit_move(&md->bl,tick,1);
mobskill_use(md, tick, MSC_SPAWN);
if (battle_config.show_mob_info&3)
@ -2883,10 +2827,7 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id)
md= mob_spawn_dataset(&data);
if(skill_id == NPC_SUMMONSLAVE){
md->master_id=md2->bl.id;
md->state.killer = md2->state.killer;
md->special_state.ai = md2->special_state.ai;
md->nd = md2->nd;
md->callback_flag = md2->callback_flag;
}
mob_spawn(md);
@ -3462,26 +3403,6 @@ int mob_clone_delete(int class_)
return 0;
}
int mob_script_callback(struct mob_data *md, struct block_list *target, short action_type)
{
// DEBUG: Uncomment these if errors occur. ---
// nullpo_retr(md, 0);
// nullpo_retr(md->nd, 0);
// -------------------------------------------
if(md->callback_flag&action_type){
int regkey = add_str(".ai_action");
linkdb_replace(&md->nd->u.scr.script->script_vars,(void *)regkey, (void *)(int)action_type);
if(target){
linkdb_replace(&md->nd->u.scr.script->script_vars,(void *)(regkey+(1<<24)), (void *)(int)target->type);
linkdb_replace(&md->nd->u.scr.script->script_vars,(void *)(regkey+(2<<24)), (void *)target->id);
}
linkdb_replace(&md->nd->u.scr.script->script_vars,(void *)(regkey+(3<<24)), (void *)md->bl.id);
run_script(md->nd->u.scr.script, 0, 0, md->nd->bl.id);
return 1;
}
return 0;
}
//
// <20>‰Šú‰»
//

View File

@ -35,19 +35,6 @@
#define MOB_CLONE_START (MAX_MOB_DB-999)
#define MOB_CLONE_END MAX_MOB_DB
// Scripted Mob AI Constants
#define CALLBACK_NPCCLICK 0x100
#define CALLBACK_ATTACK 0x80
#define CALLBACK_DETECT 0x40
#define CALLBACK_DEAD 0x20
#define CALLBACK_ASSIST 0x10
#define CALLBACK_KILL 0x08
#define CALLBACK_UNLOCK 0x04
#define CALLBACK_WALKACK 0x02
#define CALLBACK_WARPACK 0x01
int mob_script_callback(struct mob_data *md, struct block_list *target, short action_type);
struct mob_skill {
short state;
short skill_id,skill_lv;
@ -107,8 +94,6 @@ struct mob_data {
unsigned steal_coin_flag : 1;
unsigned soul_change_flag : 1; // Celest
unsigned alchemist: 1;
unsigned no_random_walk: 1;
unsigned killer: 1;
unsigned spotted: 1;
unsigned char attacked_count; //For rude attacked.
int provoke_flag; // Celest
@ -137,9 +122,6 @@ struct mob_data {
int deletetimer;
int master_id,master_dist;
struct npc_data *nd;
unsigned short callback_flag;
short skillidx;
unsigned int skilldelay[MAX_MOBSKILL];
char npc_event[50];
@ -269,7 +251,6 @@ 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_);

View File

@ -80,7 +80,6 @@ struct npc_data {
#ifdef PCRE_SUPPORT
void npc_chat_finalize(struct npc_data* nd);
int mob_chat_sub(struct block_list* bl, va_list ap);
#endif
//Script NPC events.

View File

@ -403,15 +403,6 @@ int npc_chat_sub(struct block_list* bl, va_list ap)
return 0;
}
int mob_chat_sub(struct block_list* bl, va_list ap)
{
struct mob_data *md = (struct mob_data *)bl;
if(md->nd)
npc_chat_sub(&md->nd->bl, ap);
return 0;
}
// Various script builtins used to support these functions
int buildin_defpattern(struct script_state* st)

View File

@ -4968,8 +4968,6 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
status_calc_mob(md, 0);
status_percent_heal(src,10,0);
}
if(md->nd)
mob_script_callback(md, &sd->bl, CALLBACK_KILL);
}
break;
case BL_PET: //Pass on to master...

View File

@ -12514,221 +12514,6 @@ BUILDIN_FUNC(pcstopfollow)
// [zBuffer] List of mob control commands --->
//## TODO always return if the request/whatever was successfull [FlavioJS]
BUILDIN_FUNC(mobspawn)
{
int class_,x,y,id;
const char *str,*map;
// Who?
str =script_getstr(st,2);
// What?
class_ =script_getnum(st,3);
// Where?
map =script_getstr(st,4);
x =script_getnum(st,5);
y =script_getnum(st,6);
id = mob_once_spawn(map_id2sd(st->rid),map_mapname2mapid(map),x,y,str,class_,1,"");
script_pushint(st,id);
return 0;
}
BUILDIN_FUNC(mobremove)
{
int id;
struct block_list *bl = NULL;
id = script_getnum(st,2);
bl = map_id2bl(id);
if (bl && bl->type == BL_MOB)
unit_free(bl,0);
return 0;
}
BUILDIN_FUNC(getmobdata)
{
int num, id;
char *name;
struct mob_data *md = NULL;
TBL_PC *sd = st->rid?map_id2sd(st->rid):NULL;
id = script_getnum(st,2);
if(!(md = (struct mob_data *)map_id2bl(id)) || md->bl.type != BL_MOB || !data_isreference(script_getdata(st,3)) ){
ShowWarning("buildin_getmobdata: Error in argument!\n");
return -1;
}
num=st->stack->stack_data[st->start+3].u.num;
name=(char *)(str_buf+str_data[num&0x00ffffff].str);
setd_sub(st,sd,name,0,(void *)(int)md->class_,script_getref(st,3));
setd_sub(st,sd,name,1,(void *)(int)md->level,script_getref(st,3));
setd_sub(st,sd,name,2,(void *)(int)md->status.hp,script_getref(st,3));
setd_sub(st,sd,name,3,(void *)(int)md->status.max_hp,script_getref(st,3));
setd_sub(st,sd,name,4,(void *)(int)md->master_id,script_getref(st,3));
setd_sub(st,sd,name,5,(void *)(int)md->bl.m,script_getref(st,3));
setd_sub(st,sd,name,6,(void *)(int)md->bl.x,script_getref(st,3));
setd_sub(st,sd,name,7,(void *)(int)md->bl.y,script_getref(st,3));
setd_sub(st,sd,name,8,(void *)(int)md->status.speed,script_getref(st,3));
setd_sub(st,sd,name,9,(void *)(int)md->status.mode,script_getref(st,3));
setd_sub(st,sd,name,10,(void *)(int)md->special_state.ai,script_getref(st,3));
setd_sub(st,sd,name,11,(void *)(int)md->sc.option,script_getref(st,3));
setd_sub(st,sd,name,12,(void *)(int)md->vd->sex,script_getref(st,3));
setd_sub(st,sd,name,13,(void *)(int)md->vd->class_,script_getref(st,3));
setd_sub(st,sd,name,14,(void *)(int)md->vd->hair_style,script_getref(st,3));
setd_sub(st,sd,name,15,(void *)(int)md->vd->hair_color,script_getref(st,3));
setd_sub(st,sd,name,16,(void *)(int)md->vd->head_bottom,script_getref(st,3));
setd_sub(st,sd,name,17,(void *)(int)md->vd->head_mid,script_getref(st,3));
setd_sub(st,sd,name,18,(void *)(int)md->vd->head_top,script_getref(st,3));
setd_sub(st,sd,name,19,(void *)(int)md->vd->cloth_color,script_getref(st,3));
setd_sub(st,sd,name,20,(void *)(int)md->vd->shield,script_getref(st,3));
setd_sub(st,sd,name,21,(void *)(int)md->vd->weapon,script_getref(st,3));
setd_sub(st,sd,name,22,(void *)(int)md->vd->shield,script_getref(st,3));
setd_sub(st,sd,name,23,(void *)(int)md->ud.dir,script_getref(st,3));
setd_sub(st,sd,name,24,(void *)(int)md->state.killer,script_getref(st,3));
setd_sub(st,sd,name,25,(void *)(int)md->callback_flag,script_getref(st,3));
setd_sub(st,sd,name,26,(void *)(int)md->state.no_random_walk, script_getref(st,3));
return 0;
}
/// Changes the data of a mob
///
/// setmobdata <mob unit id>,<type>,<value>;
BUILDIN_FUNC(setmobdata)
{
struct block_list* mob_bl;
mob_bl = map_id2bl(script_getnum(st,2));
if( mob_bl != NULL && mob_bl->type == BL_MOB )
{
TBL_MOB* md = (TBL_MOB*)mob_bl;
int type;
int value;
type = script_getnum(st,3);
value = script_getnum(st,4);
switch( type )
{
case 0: md->class_ = (short)value; break;
case 1: md->level = (unsigned short)value; break;
case 2: md->status.hp = (unsigned int)value; break;
case 3: md->status.max_hp = (unsigned int)value; break;
case 4: md->master_id = value; break;
case 5: md->bl.m = (short)value; break;
case 6: md->bl.x = (short)value; break;
case 7: md->bl.y = (short)value; break;
case 8: md->status.speed = (unsigned short)value; break;
case 9: md->status.mode = (unsigned short)value; break;
case 10: md->special_state.ai = (unsigned int)value; break;
case 11: md->sc.option = (unsigned short)value; break;
case 12: md->vd->sex = (char)value; break;
case 13: md->vd->class_ = (unsigned short)value; break;
case 14: md->vd->hair_style = (unsigned short)value; break;
case 15: md->vd->hair_color = (unsigned short)value; break;
case 16: md->vd->head_bottom = (unsigned short)value; break;
case 17: md->vd->head_mid = (unsigned short)value; break;
case 18: md->vd->head_top = (unsigned short)value; break;
case 19: md->vd->cloth_color = (unsigned short)value; break;
case 20: md->vd->shield = (unsigned short)value; break;
case 21: md->vd->weapon = (unsigned short)value; break;
case 22: md->vd->shield = (unsigned short)value; break;
case 23: md->ud.dir = (unsigned char)value; break;
case 24: md->state.killer = value > 0 ? 1 : 0; break;
case 25: md->callback_flag = (short)value; break;
case 26: md->state.no_random_walk = value > 0 ? 1 : 0; break;
default:
ShowError("script:setmobdata: unknown data identifier %d\n", type);
return 1;
}
}
return 0;
}
/// Makes the mob assist the target unit as a slave
///
/// mobassist <mob unit id>,"<player name>";
/// mobassist <mob unit id>,<target id>;
BUILDIN_FUNC(mobassist)
{
struct block_list* mob_bl;
// get mob
mob_bl = map_id2bl(script_getnum(st,2));
if( mob_bl != NULL && mob_bl->type == BL_MOB )
{
TBL_MOB* md = (TBL_MOB*)mob_bl;
struct block_list* target_bl = NULL;
struct script_data* data;
// get target
data = script_getdata(st, 3);
get_val(st, data);
if( data_isstring(data) )
{
TBL_PC* sd = map_nick2sd(conv_str(st, data));
if( sd != NULL )
target_bl = &sd->bl;
}
if( target_bl == NULL )
target_bl = map_id2bl(conv_num(st, data));
// set mob as slave
if( target_bl != NULL )
{
struct unit_data* ud;
md->master_id = target_bl->id;
md->state.killer = 1;
mob_convertslave(md);
ud = unit_bl2ud(mob_bl);
if( ud != NULL )
{
if( ud->target != 0 )
md->target_id = ud->target;
else if( ud->skilltarget != 0 )
md->target_id = ud->skilltarget;
if( md->target_id != 0 )
unit_walktobl(&md->bl, map_id2bl(md->target_id), 65025, 2);
}
}
}
return 0;
}
/// Attaches the current npc or the target npc to the mob unit
///
/// mobattach <mob unit id>{,"<npc name>"};
BUILDIN_FUNC(mobattach)
{
struct block_list* mob_bl;
mob_bl = map_id2bl(script_getnum(st,2));
if( mob_bl != NULL && mob_bl->type == BL_MOB )
{
TBL_MOB* md = (TBL_MOB*)mob_bl;
TBL_NPC* nd = NULL;
if( script_hasdata(st,3) )
nd = npc_name2id(script_getstr(st, 3));
else
{
struct block_list* npc_bl = map_id2bl(st->oid);
if( npc_bl != NULL && npc_bl->type == BL_NPC )
nd = (TBL_NPC*)npc_bl;
}
if( nd != NULL )
md->nd = nd;
}
return 0;
}
/// Makes the unit walk to target position or map
/// Returns if it was successfull
///
@ -12844,7 +12629,6 @@ BUILDIN_FUNC(unitattack)
script_pushint(st, 1);
return 0;
case BL_MOB:
((TBL_MOB *)unit_bl)->state.killer = 1;
((TBL_MOB *)unit_bl)->target_id = target_bl->id;
break;
case BL_PET:
@ -13636,12 +13420,6 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(pcblockmove,"ii"),
// <--- [zBuffer] List of player cont commands
// [zBuffer] List of mob control commands --->
BUILDIN_DEF(mobspawn,"*"),
BUILDIN_DEF(mobremove,"i"),
BUILDIN_DEF(getmobdata,"i*"),
BUILDIN_DEF(setmobdata,"iii"),
BUILDIN_DEF(mobassist,"i?"),
BUILDIN_DEF(mobattach,"i?"),
BUILDIN_DEF(unitwalk,"ii?"),
BUILDIN_DEF(unitkill,"i"),
BUILDIN_DEF(unitwarp,"isii"),

View File

@ -256,8 +256,6 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr data)
else { //Stopped walking. Update to_x and to_y to current location [Skotlex]
ud->to_x = bl->x;
ud->to_y = bl->y;
if(md && md->nd) // Tell the script engine we've finished walking (for AI pathfinding)
mob_script_callback(md, NULL, CALLBACK_WALKACK);
}
return 0;
}
@ -630,11 +628,6 @@ int unit_warp(struct block_list *bl,short m,short x,short y,int type)
clif_spawn(bl);
skill_unit_move(bl,gettick(),1);
if(bl->type == BL_MOB){
TBL_MOB *md = (TBL_MOB *)bl;
if(md->nd) // Tell the script engine we've warped
mob_script_callback(md, NULL, CALLBACK_WARPACK);
}
return 0;
}