diff --git a/doc/mob_db_mode_list.txt b/doc/mob_db_mode_list.txt index a17c919aec..27a4cf1877 100644 --- a/doc/mob_db_mode_list.txt +++ b/doc/mob_db_mode_list.txt @@ -33,6 +33,8 @@ MD_IGNORERANGED | 0x040000 | 262144 MD_MVP | 0x080000 | 524288 MD_IGNOREMISC | 0x100000 | 1048576 MD_KNOCKBACK_IMMUNE | 0x200000 | 2097152 +MD_NORANDOM_WALK | 0x400000 | 4194304 +MD_NOCAST_SKILL | 0x800000 | 8388608 Explanation for modes diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 47d6fc6e15..fd4bb38ed6 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -2334,11 +2334,11 @@ character name is specified, of that player. Type is the kind of associated ID number required: - 0 - Character ID number. - 1 - Party ID number. - 2 - Guild ID number. - 3 - Account ID number. - 4 - Battle ground ID + 0 - Character ID + 1 - Party ID + 2 - Guild ID + 3 - Account ID + 4 - Battle Ground ID For most purposes other than printing it, a number is better to have than a name (people do horrifying things to their character names). @@ -2363,7 +2363,7 @@ Retrieves IDs of the currently invoked NPC. If a unique npc name is given, IDs of that NPC are retrieved instead. Type specifies what ID to retrieve and can be one of the following: - 0 - Unit ID (GID) + 0 - NPC Game ID If an invalid type is given or the NPC does not exist, 0 is returned. @@ -5588,6 +5588,9 @@ The 'areamonster' command works much like the 'monster' command and is not significantly different, but spawns the monsters within a square defined by x1/y1-x2/y2. +Returned value is an array with the game ID of the spawned monster(s) depending +on the amount spawned. Array is stored in $@mobid[]. + Simple monster killing script: @@ -5757,6 +5760,8 @@ and it is not possible to create a spawn that lasts forever. If an event label is given, upon the monster being killed, the event label will run as if by 'donpcevent'. +Returned value is the game ID of the spawned monster. + // Will summon a dead branch-style monster to fight for the character. summon "--ja--",-1; @@ -6999,9 +7004,15 @@ OnTouch: --------------------------------------- -*unitstop ; +*unitstopattack ; -This command will make a stop attacking and moving. +This command will make a stop attacking. + +--------------------------------------- + +*unitstopwalk ; + +This command will make a stop moving. --------------------------------------- @@ -7018,16 +7029,123 @@ For a full list of emotion numbers, see 'db/const.txt' under 'e_'. --------------------------------------- -*unitskilluseid ,,{,}; -*unitskilluseid ,"",{,}; -*unitskillusepos ,,,,; -*unitskillusepos ,"",,,; +*unitskilluseid ,,{,,}; +*unitskilluseid ,"",{,,}; +*unitskillusepos ,,,,{,}; +*unitskillusepos ,"",,,{,}; This is the replacement of the older commands, these use the same values for GID as the other unit* commands (See 'GID'). Skill ID is the ID of the skill, skill level is the level of the skill. -For the position, the x and y are given in the unitSkillUsePos. +Cast time is the amount of seconds to add or remove from the skill. Use a positive value to +add and negative value to subtract. Using 0 or no value will use the default skill cast time. +For the position, the x and y are given in the UnitSkillUsePos. + +--------------------------------------- + +*getunitname ; + +Gets the name of the given unit. Supported types are monster, homunculus, pet, and NPC. +Mercenary and Elemental don't support custom names. + +Returns "Unknown" if unit is not found. + +--------------------------------------- + +*setunitname ,""; + +Changes the name of the given unit to the new name given. Supported types are monster, +homunculus, and pet. To change an NPC's name, see 'setnpcdisplay'. Mercenary and +Elemental don't support custom names. + +Changing a homunculus or pet name will be permanent. + +--------------------------------------- + +*getunitdata ,; +*setsetdata ,,; + +This is used to get and set special data related to the unit. +With getunitdata, the array given will be filled with the current data. In setunitdata +the indexes in the array would be used to set that data on the unit. + +Parameters (indexes) for monsters are: + + 0 - size (big, small, normal) 7 - y 14 - hair style 21 - weapon 28 - DEX + 1 - level 8 - speed 15 - hair color 22 - shield (again) 29 - LUK + 2 - HP 9 - mode 16 - head gear bottom 23 - looking dir 30 - for slave to copy master's mode + 3 - max HP 10 - special AI state 17 - head gear middle 24 - STR 31 - immune from attacks state + 4 - master AID 11 - SC option 18 - head gear top 25 - AGI + 5 - map index 12 - sex 19 - cloth color 26 - VIT + 6 - x 13 - class (Monster ID, Job ID) 20 - shield 27 - INT + +Parameter (indexes) for homunculi are: + + 0 - size (big, small, normal) 7 - map index 14 - canmove_tick 21 - immune from attacks state + 1 - level 8 - x 15 - STR + 2 - HP 9 - y 16 - AGI + 3 - max HP 10 - hunger 17 - VIT + 4 - SP 11 - intimacy 18 - INT + 5 - max SP 12 - speed 19 - DEX + 6 - master Character ID 13 - looking dir 20 - LUK + +Parameter (indexes) for pets are: + + 0 - size (big, small, normal) 7 - y 14 - AGI + 1 - level 8 - hunger 15 - VIT + 2 - HP 9 - intimacy 16 - INT + 3 - max HP 10 - speed 17 - DEX + 4 - master AID 11 - looking dir 18 - LUK + 5 - map index 12 - canmove_tick 19 - name + 6 - x 13 - STR + +Parameter (indexes) for mercenaries are: + + 0 - size (big, small, normal) 7 - y 14 - AGI + 1 - level 8 - kill count 15 - VIT + 2 - HP 9 - life time 16 - INT + 3 - max HP 10 - speed 17 - DEX + 4 - master Character ID 11 - looking dir 18 - LUK + 5 - map index 12 - canmove_tick 19 - immune from attacks state + 6 - x 13 - STR + +Parameter (indexes) for elementals are: + + 0 - size (big, small, normal) 7 - map index 14 - canmove_tick 21 - immune from attacks state + 1 - level 8 - x 15 - STR + 2 - HP 9 - y 16 - AGI + 3 - max HP 10 - life time 17 - VIT + 4 - SP 11 - mode 18 - INT + 5 - max SP 12 - speed 19 - DEX + 6 - master Character ID 13 - looking dir 20 - LUK + +Parameter (indexes) for NPCs are: + + 0 - display 7 - looking dir + 1 - level 8 - STR + 2 - HP 9 - AGI + 3 - max HP 10 - VIT + 4 - map index 11 - INT + 5 - x 12 - DEX + 6 - y 13 - LUK + +*Note: For mode, see doc/mob_db_mode_list.txt + +Example: + // Spawn some Porings and save the Game ID. + // - Keep in mind, when the 'monster' script command is used, + // - all the spawned monster GID's are stored in an array + // - called $@mobid[]. + monster "prontera",123,42,"Poring",1002,10; + .GID = $@mobid[9]; // Store and modify the 10th Poring spawned to make him stronger! + + // Save the strong Poring's mob data in the @por_arr[] variable. (@por_arr[1] being level, @por_arr[13] being class, etc.) + getunitdata .GID,@por_arr; + + // Set the max HP of the Poring to 1000 and update the current HP to match. + setunitdata .GID,3,1000; + setunitdata .GID,2,1000; --------------------------------------- \\ @@ -8044,9 +8162,7 @@ server and the egg will disappear when anyone tries to hatch it. This function will return pet information for the pet the invoking character currently has active. Valid types are: - 0 - Unique pet ID number as stored by the char server and distinguishing it - from all other pets the characters actually have. This value is currently - useless, at most you can use it to tell pets apart reliably. + 0 - Pet Game ID 1 - Pet class number as per 'db/pet_db.txt' - will tell you what kind of a pet it is. 2 - Pet name. Will return "null" if there's no pet. @@ -8055,7 +8171,6 @@ currently has active. Valid types are: 5 - Pet rename flag. 0 means this pet has not been named yet. 6 - Pet level - --------------------------------------- ============================= @@ -8217,12 +8332,12 @@ invoking character, regardless of its vaporize state. It returns zero or "null" if the player does not own a Homunculus. Valid types are: - 0 - Homunculus unique ID + 0 - Homunculus Game ID 1 - Homunculus Class - 2 - Name - 3 - Friendly level (intimacy score). 100000 is full loyalty. - 4 - Hungry level. 100 is completely full. - 5 - Rename flag. 0 means this homunculus has not been named yet. + 2 - Homunculus Name + 3 - Homunculus friendly level (intimacy score). 100000 is full loyalty. + 4 - Homunculus hungry level. 100 is completely full. + 5 - Homunculus rename flag. 0 means this homunculus has not been named yet. 6 - Homunculus level --------------------------------------- @@ -8246,6 +8361,8 @@ list of all available classes, see 'db/mercenary_db.txt'. This command is typically used in item scripts of mercenary scrolls. +Returned value is the game ID of the spawned mercenary. + --------------------------------------- *mercenary_heal ,; @@ -8293,14 +8410,14 @@ character. If char id is given, the information of that character is retrieved instead. Type specifies what information to retrieve and can be one of the following: - 0 - Database ID - 1 - Class - 2 - Name - 3 - Faith value for this mercenary's guild, if any - 4 - Calls value for this mercenary's guild, if any - 5 - Kill count - 6 - Remaining life time in msec - 7 - Level + 0 - Mercenary Game ID + 1 - Mercenary Class + 2 - Mercenary Name + 3 - Mercenary faith value for this mercenary's guild, if any + 4 - Mercenary calls value for this mercenary's guild, if any + 5 - Mercenary kill count + 6 - Mercenary remaining life time in msec + 7 - Mercenary level If the character does not have a mercenary, the command returns "" for name and 0 for all other types. diff --git a/src/map/battle.c b/src/map/battle.c index 0e39139499..beef1e12b7 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7142,10 +7142,12 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f int state = 0; //Initial state none int strip_enemy = 1; //Flag which marks whether to remove the BCT_ENEMY status if it's also friend/ally. struct block_list *s_bl = src, *t_bl = target; + struct unit_data *ud = NULL; nullpo_ret(src); nullpo_ret(target); + ud = unit_bl2ud(target); m = target->m; //t_bl/s_bl hold the 'master' of the attack, while src/target are the actual @@ -7174,6 +7176,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f switch( target->type ) { // Checks on actual target case BL_PC: { struct status_change* sc = status_get_sc(src); + if (((TBL_PC*)target)->invincible_timer != INVALID_TIMER || pc_isinvisible((TBL_PC*)target)) return -1; //Cannot be targeted yet. if( sc && sc->count ) { @@ -7185,6 +7188,9 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f case BL_MOB: { struct mob_data *md = ((TBL_MOB*)target); + + if (ud && ud->immune_attack) + return 0; if(((md->special_state.ai == AI_SPHERE || //Marine Spheres (md->special_state.ai == AI_FLORA && battle_config.summon_flora&1)) && s_bl->type == BL_PC && src->type != BL_MOB) || //Floras (md->special_state.ai == AI_ZANZOU && t_bl->id != s_bl->id) || //Zanzoe @@ -7256,10 +7262,11 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f return 0; } break; - //Valid targets with no special checks here. case BL_MER: case BL_HOM: case BL_ELEM: + if (ud && ud->immune_attack) + return 0; break; //All else not specified is an invalid target. default: diff --git a/src/map/map.c b/src/map/map.c index 7ae0fda396..1e4ec44128 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1903,6 +1903,11 @@ struct pet_data* map_id2pd(int id){ return BL_CAST(BL_PET, bl); } +struct elemental_data* map_id2ed(int id) { + struct block_list* bl = map_id2bl(id); + return BL_CAST(BL_ELEM, bl); +} + struct chat_data* map_id2cd(int id){ struct block_list* bl = map_id2bl(id); return BL_CAST(BL_CHAT, bl); diff --git a/src/map/map.h b/src/map/map.h index 241c42a75a..973a80abfc 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -836,6 +836,8 @@ struct mob_data * map_id2md(int id); struct npc_data * map_id2nd(int id); struct homun_data* map_id2hd(int id); struct mercenary_data* map_id2mc(int id); +struct pet_data* map_id2pd(int id); +struct elemental_data* map_id2ed(int id); struct chat_data* map_id2cd(int id); struct block_list * map_id2bl(int id); bool map_blid_exists( int id ); diff --git a/src/map/mob.c b/src/map/mob.c index 2dd27db1e3..200f347791 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1353,6 +1353,7 @@ int mob_randomwalk(struct mob_data *md,unsigned int tick) nullpo_ret(md); if(DIFF_TICK(md->next_walktime,tick)>0 || + (status_get_mode(&md->bl)&MD_NORANDOM_WALK) || !unit_can_move(&md->bl) || !(status_get_mode(&md->bl)&MD_CANMOVE)) return 0; @@ -3048,6 +3049,9 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id) } } + if (md2->state.copy_master_mode) + md->status.mode = md2->status.mode; + clif_skill_nodamage(&md->bl,&md->bl,skill_id,amount,1); } @@ -3185,7 +3189,7 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event) nullpo_ret(md); nullpo_ret(ms = md->db->skill); - if (!battle_config.mob_skill_rate || md->ud.skilltimer != INVALID_TIMER || !md->db->maxskill) + if (!battle_config.mob_skill_rate || md->ud.skilltimer != INVALID_TIMER || !md->db->maxskill || (status_get_mode(&md->bl)&MD_NOCAST_SKILL)) return 0; if (event == -1 && DIFF_TICK(md->ud.canact_tick, tick) > 0) diff --git a/src/map/mob.h b/src/map/mob.h index b8dbcfcc01..3f44e513c6 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -143,6 +143,7 @@ struct mob_data { unsigned int npc_killmonster: 1; //for new killmonster behavior unsigned int rebirth: 1; // NPC_Rebirth used unsigned int boss : 1; + unsigned int copy_master_mode : 1; ///< Whether the spawned monster should copy the master's mode. enum MobSkillState skillstate; unsigned char steal_flag; //number of steal tries (to prevent steal exploit on mobs with few items) [Lupus] unsigned char attacked_count; //For rude attacked. @@ -187,8 +188,6 @@ struct mob_data { int tomb_nid; }; - - enum { MST_TARGET = 0, MST_RANDOM, //Random Target! diff --git a/src/map/script.c b/src/map/script.c index 7d7260de0e..e4d1a27bd5 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -7480,6 +7480,7 @@ BUILDIN_FUNC(getcharid) } return SCRIPT_CMD_SUCCESS; } + /*========================================== * returns the GID of an NPC *------------------------------------------*/ @@ -9263,6 +9264,7 @@ BUILDIN_FUNC(cooking) clif_cooking_list(sd, trigger, AM_PHARMACY, 1, 1); return SCRIPT_CMD_SUCCESS; } + /*========================================== * Create a pet *------------------------------------------*/ @@ -9291,6 +9293,7 @@ BUILDIN_FUNC(makepet) return SCRIPT_CMD_SUCCESS; } + /*========================================== * Give player exp base,job * quest_exp_rate/100 *------------------------------------------*/ @@ -9362,13 +9365,8 @@ BUILDIN_FUNC(guildchangegm) } /*========================================== - * Spawn a monster : + * Spawn a monster: * *monster "",,,"",,{,"",,}; - @mapn,x,y : location - @str : monster name - @class_ : mob_id - @amount : nb to spawn - @event : event to attach to mob *------------------------------------------*/ BUILDIN_FUNC(monster) { @@ -9419,12 +9417,16 @@ BUILDIN_FUNC(monster) else m = map_mapname2mapid(mapn); - for(i=0; i 0:pet_id 1:pet_class 2:pet_name @@ -14103,6 +14116,8 @@ BUILDIN_FUNC(summon) clif_specialeffect(&md->bl,344,AREA); sc_start4(NULL,&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000); } + script_pushint(st, md->bl.id); + return SCRIPT_CMD_SUCCESS; } @@ -16165,10 +16180,546 @@ BUILDIN_FUNC(pcstopfollow) return SCRIPT_CMD_SUCCESS; } // <--- [zBuffer] List of player cont commands -// [zBuffer] List of mob control commands ---> +// [zBuffer] List of unit control commands ---> -/// Makes the unit walk to target position or map -/// Returns if it was successfull +/// Gets specific live information of a bl. +/// +/// getunitdata ,; +BUILDIN_FUNC(getunitdata) +{ + TBL_PC *sd = st->rid ? map_id2sd(st->rid) : NULL; + struct block_list* bl; + TBL_MOB* md = NULL; + TBL_HOM* hd = NULL; + TBL_MER* mc = NULL; + TBL_PET* pd = NULL; + TBL_ELEM* ed = NULL; + TBL_NPC* nd = NULL; + int num; + char* name; + + if (!data_isreference(script_getdata(st, 3))) { + ShowWarning("buildin_getunitdata: Error in argument! Please give a variable to store values in.\n"); + return SCRIPT_CMD_FAILURE; + } + + bl = map_id2bl(script_getnum(st, 2)); + + if (!bl) { + ShowWarning("buildin_getunitdata: Error in finding object with given game ID %d!\n", script_getnum(st, 2)); + return SCRIPT_CMD_FAILURE; + } + + switch (bl->type) { + case BL_MOB: md = map_id2md(bl->id); break; + case BL_HOM: hd = map_id2hd(bl->id); break; + case BL_PET: pd = map_id2pd(bl->id); break; + case BL_MER: mc = map_id2mc(bl->id); break; + case BL_ELEM: ed = map_id2ed(bl->id); break; + case BL_NPC: nd = map_id2nd(bl->id); break; + } + + num = st->stack->stack_data[st->start+3].u.num; + name = (char *)(str_buf+str_data[num&0x00ffffff].str); + + switch(bl->type) { + case BL_MOB: + if (!md) { + ShowWarning("buildin_getunitdata: Error in finding object BL_MOB!\n"); + return SCRIPT_CMD_FAILURE; + } + setd_sub(st,sd,name,0,(void *)(int)md->status.size,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->status.str, script_getref(st,3)); + setd_sub(st,sd,name,25,(void *)(int)md->status.agi, script_getref(st,3)); + setd_sub(st,sd,name,26,(void *)(int)md->status.vit, script_getref(st,3)); + setd_sub(st,sd,name,27,(void *)(int)md->status.int_, script_getref(st,3)); + setd_sub(st,sd,name,28,(void *)(int)md->status.dex, script_getref(st,3)); + setd_sub(st,sd,name,29,(void *)(int)md->status.luk, script_getref(st,3)); + setd_sub(st,sd,name,30,(void *)(int)md->state.copy_master_mode, script_getref(st,3)); + setd_sub(st,sd,name,31,(void *)(int)md->ud.immune_attack, script_getref(st,3)); + break; + + case BL_HOM: + if (!hd) { + ShowWarning("buildin_getunitdata: Error in finding object BL_HOM!\n"); + return SCRIPT_CMD_FAILURE; + } + setd_sub(st,sd,name,0,(void *)(int)hd->base_status.size,script_getref(st,3)); + setd_sub(st,sd,name,1,(void *)(int)hd->homunculus.level,script_getref(st,3)); + setd_sub(st,sd,name,2,(void *)(int)hd->homunculus.hp,script_getref(st,3)); + setd_sub(st,sd,name,3,(void *)(int)hd->homunculus.max_hp,script_getref(st,3)); + setd_sub(st,sd,name,4,(void *)(int)hd->homunculus.sp,script_getref(st,3)); + setd_sub(st,sd,name,5,(void *)(int)hd->homunculus.max_sp,script_getref(st,3)); + setd_sub(st,sd,name,6,(void *)(int)hd->homunculus.char_id,script_getref(st,3)); + setd_sub(st,sd,name,7,(void *)(int)hd->bl.m,script_getref(st,3)); + setd_sub(st,sd,name,8,(void *)(int)hd->bl.x,script_getref(st,3)); + setd_sub(st,sd,name,9,(void *)(int)hd->bl.y,script_getref(st,3)); + setd_sub(st,sd,name,10,(void *)(int)hd->homunculus.hunger,script_getref(st,3)); + setd_sub(st,sd,name,11,(void *)(int)hd->homunculus.intimacy,script_getref(st,3)); + setd_sub(st,sd,name,12,(void *)(int)hd->base_status.speed,script_getref(st,3)); + setd_sub(st,sd,name,13,(void *)(int)hd->ud.dir,script_getref(st,3)); + setd_sub(st,sd,name,14,(void *)(int)hd->ud.canmove_tick, script_getref(st,3)); + setd_sub(st,sd,name,15,(void *)(int)hd->base_status.str, script_getref(st,3)); + setd_sub(st,sd,name,16,(void *)(int)hd->base_status.agi, script_getref(st,3)); + setd_sub(st,sd,name,17,(void *)(int)hd->base_status.vit, script_getref(st,3)); + setd_sub(st,sd,name,18,(void *)(int)hd->base_status.int_, script_getref(st,3)); + setd_sub(st,sd,name,19,(void *)(int)hd->base_status.dex, script_getref(st,3)); + setd_sub(st,sd,name,20,(void *)(int)hd->base_status.luk, script_getref(st,3)); + setd_sub(st,sd,name,21,(void *)(int)hd->ud.immune_attack, script_getref(st,3)); + break; + + case BL_PET: + if (!pd) { + ShowWarning("buildin_getunitdata: Error in finding object BL_PET!\n"); + return SCRIPT_CMD_FAILURE; + } + setd_sub(st,sd,name,0,(void *)(int)pd->status.size,script_getref(st,3)); + setd_sub(st,sd,name,1,(void *)(int)pd->pet.level,script_getref(st,3)); + setd_sub(st,sd,name,2,(void *)(int)pd->status.hp,script_getref(st,3)); + setd_sub(st,sd,name,3,(void *)(int)pd->status.max_hp,script_getref(st,3)); + setd_sub(st,sd,name,4,(void *)(int)pd->pet.account_id,script_getref(st,3)); + setd_sub(st,sd,name,5,(void *)(int)pd->bl.m,script_getref(st,3)); + setd_sub(st,sd,name,6,(void *)(int)pd->bl.x,script_getref(st,3)); + setd_sub(st,sd,name,7,(void *)(int)pd->bl.y,script_getref(st,3)); + setd_sub(st,sd,name,8,(void *)(int)pd->pet.hungry,script_getref(st,3)); + setd_sub(st,sd,name,9,(void *)(int)pd->pet.intimate,script_getref(st,3)); + setd_sub(st,sd,name,10,(void *)(int)pd->status.speed,script_getref(st,3)); + setd_sub(st,sd,name,11,(void *)(int)pd->ud.dir,script_getref(st,3)); + setd_sub(st,sd,name,12,(void *)(int)pd->ud.canmove_tick, script_getref(st,3)); + setd_sub(st,sd,name,13,(void *)(int)pd->status.str, script_getref(st,3)); + setd_sub(st,sd,name,14,(void *)(int)pd->status.agi, script_getref(st,3)); + setd_sub(st,sd,name,15,(void *)(int)pd->status.vit, script_getref(st,3)); + setd_sub(st,sd,name,16,(void *)(int)pd->status.int_, script_getref(st,3)); + setd_sub(st,sd,name,17,(void *)(int)pd->status.dex, script_getref(st,3)); + setd_sub(st,sd,name,18,(void *)(int)pd->status.luk, script_getref(st,3)); + break; + + case BL_MER: + if (!mc) { + ShowWarning("buildin_getunitdata: Error in finding object BL_MER!\n"); + return SCRIPT_CMD_FAILURE; + } + setd_sub(st,sd,name,0,(void *)(int)mc->base_status.size,script_getref(st,3)); + setd_sub(st,sd,name,1,(void *)(int)mc->base_status.hp,script_getref(st,3)); + setd_sub(st,sd,name,2,(void *)(int)mc->base_status.max_hp,script_getref(st,3)); + setd_sub(st,sd,name,3,(void *)(int)mc->mercenary.char_id,script_getref(st,3)); + setd_sub(st,sd,name,4,(void *)(int)mc->bl.m,script_getref(st,3)); + setd_sub(st,sd,name,5,(void *)(int)mc->bl.x,script_getref(st,3)); + setd_sub(st,sd,name,6,(void *)(int)mc->bl.y,script_getref(st,3)); + setd_sub(st,sd,name,7,(void *)(int)mc->mercenary.kill_count,script_getref(st,3)); + setd_sub(st,sd,name,8,(void *)(int)mc->mercenary.life_time,script_getref(st,3)); + setd_sub(st,sd,name,9,(void *)(int)mc->base_status.speed,script_getref(st,3)); + setd_sub(st,sd,name,10,(void *)(int)mc->ud.dir,script_getref(st,3)); + setd_sub(st,sd,name,11,(void *)(int)mc->ud.canmove_tick, script_getref(st,3)); + setd_sub(st,sd,name,12,(void *)(int)mc->base_status.str, script_getref(st,3)); + setd_sub(st,sd,name,13,(void *)(int)mc->base_status.agi, script_getref(st,3)); + setd_sub(st,sd,name,14,(void *)(int)mc->base_status.vit, script_getref(st,3)); + setd_sub(st,sd,name,15,(void *)(int)mc->base_status.int_, script_getref(st,3)); + setd_sub(st,sd,name,16,(void *)(int)mc->base_status.dex, script_getref(st,3)); + setd_sub(st,sd,name,17,(void *)(int)mc->base_status.luk, script_getref(st,3)); + setd_sub(st,sd,name,18,(void *)(int)mc->ud.immune_attack, script_getref(st,3)); + break; + + case BL_ELEM: + if (!ed) { + ShowWarning("buildin_getunitdata: Error in finding object BL_ELEM!\n"); + return SCRIPT_CMD_FAILURE; + } + setd_sub(st,sd,name,0,(void *)(int)ed->base_status.size,script_getref(st,3)); + setd_sub(st,sd,name,1,(void *)(int)ed->elemental.hp,script_getref(st,3)); + setd_sub(st,sd,name,2,(void *)(int)ed->elemental.max_hp,script_getref(st,3)); + setd_sub(st,sd,name,3,(void *)(int)ed->elemental.sp,script_getref(st,3)); + setd_sub(st,sd,name,4,(void *)(int)ed->elemental.max_sp,script_getref(st,3)); + setd_sub(st,sd,name,5,(void *)(int)ed->elemental.char_id,script_getref(st,3)); + setd_sub(st,sd,name,6,(void *)(int)ed->bl.m,script_getref(st,3)); + setd_sub(st,sd,name,7,(void *)(int)ed->bl.x,script_getref(st,3)); + setd_sub(st,sd,name,8,(void *)(int)ed->bl.y,script_getref(st,3)); + setd_sub(st,sd,name,9,(void *)(int)ed->elemental.life_time,script_getref(st,3)); + setd_sub(st,sd,name,10,(void *)(int)ed->elemental.mode,script_getref(st,3)); + setd_sub(st,sd,name,11,(void *)(int)ed->base_status.speed,script_getref(st,3)); + setd_sub(st,sd,name,12,(void *)(int)ed->ud.dir,script_getref(st,3)); + setd_sub(st,sd,name,13,(void *)(int)ed->ud.canmove_tick, script_getref(st,3)); + setd_sub(st,sd,name,14,(void *)(int)ed->base_status.str, script_getref(st,3)); + setd_sub(st,sd,name,15,(void *)(int)ed->base_status.agi, script_getref(st,3)); + setd_sub(st,sd,name,16,(void *)(int)ed->base_status.vit, script_getref(st,3)); + setd_sub(st,sd,name,17,(void *)(int)ed->base_status.int_, script_getref(st,3)); + setd_sub(st,sd,name,18,(void *)(int)ed->base_status.dex, script_getref(st,3)); + setd_sub(st,sd,name,19,(void *)(int)ed->base_status.luk, script_getref(st,3)); + setd_sub(st,sd,name,20,(void *)(int)ed->ud.immune_attack, script_getref(st,3)); + break; + + case BL_NPC: + if (!nd) { + ShowWarning("buildin_getunitdata: Error in finding object BL_NPC!\n"); + return SCRIPT_CMD_FAILURE; + } + setd_sub(st,sd,name,0,(void *)(int)nd->class_,script_getref(st,3)); + setd_sub(st,sd,name,1,(void *)(int)nd->level,script_getref(st,3)); + setd_sub(st,sd,name,2,(void *)(int)nd->status.hp,script_getref(st,3)); + setd_sub(st,sd,name,3,(void *)(int)nd->status.max_hp,script_getref(st,3)); + setd_sub(st,sd,name,4,(void *)(int)nd->bl.m,script_getref(st,3)); + setd_sub(st,sd,name,5,(void *)(int)nd->bl.x,script_getref(st,3)); + setd_sub(st,sd,name,6,(void *)(int)nd->bl.y,script_getref(st,3)); + setd_sub(st,sd,name,7,(void *)(int)nd->ud.dir,script_getref(st,3)); + setd_sub(st,sd,name,8,(void *)(int)nd->status.str, script_getref(st,3)); + setd_sub(st,sd,name,9,(void *)(int)nd->status.agi, script_getref(st,3)); + setd_sub(st,sd,name,10,(void *)(int)nd->status.vit, script_getref(st,3)); + setd_sub(st,sd,name,11,(void *)(int)nd->status.int_, script_getref(st,3)); + setd_sub(st,sd,name,12,(void *)(int)nd->status.dex, script_getref(st,3)); + setd_sub(st,sd,name,13,(void *)(int)nd->status.luk, script_getref(st,3)); + break; + + default: + ShowWarning("buildin_getunitdata: Unknown object type!\n"); + return SCRIPT_CMD_FAILURE; + } + + return SCRIPT_CMD_SUCCESS; +} + +/// Changes the live data of a bl. +/// +/// setunitdata ,,; +BUILDIN_FUNC(setunitdata) +{ + struct block_list* bl = NULL; + TBL_MOB* md = NULL; + TBL_HOM* hd = NULL; + TBL_MER* mc = NULL; + TBL_PET* pd = NULL; + TBL_ELEM* ed = NULL; + TBL_NPC* nd = NULL; + int type, value; + + bl = map_id2bl(script_getnum(st, 2)); + + if (!bl) { + ShowWarning("buildin_setunitdata: Error in finding object with given game ID %d!\n", script_getnum(st, 2)); + return SCRIPT_CMD_FAILURE; + } + + switch (bl->type) { + case BL_MOB: md = map_id2md(bl->id); break; + case BL_HOM: hd = map_id2hd(bl->id); break; + case BL_PET: pd = map_id2pd(bl->id); break; + case BL_MER: mc = map_id2mc(bl->id); break; + case BL_ELEM: ed = map_id2ed(bl->id); break; + case BL_NPC: nd = map_id2nd(bl->id); break; + } + + type = script_getnum(st, 3); + value = script_getnum(st, 4); + + switch (bl->type) { + case BL_MOB: + if (!md) { + ShowWarning("buildin_setunitdata: Error in finding object BL_MOB!\n"); + return SCRIPT_CMD_FAILURE; + } + switch (type) { + case 0: md->status.size = (unsigned char)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 = (enum e_mode)value; break; + case 10: md->special_state.ai = (enum mob_ai)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->status.str = (unsigned int)value; break; + case 25: md->status.agi = (unsigned int)value; break; + case 26: md->status.vit = (unsigned int)value; break; + case 27: md->status.int_ = (unsigned int)value; break; + case 28: md->status.dex = (unsigned int)value; break; + case 29: md->status.luk = (unsigned int)value; break; + case 30: md->state.copy_master_mode = value > 0 ? 1 : 0; break; + case 31: md->ud.immune_attack = (bool)value > 0 ? 1 : 0; break; + default: + ShowError("buildin_setunitdata: Unknown data identifier %d for BL_MOB.\n", type); + return SCRIPT_CMD_FAILURE; + } + break; + + case BL_HOM: + if (!hd) { + ShowWarning("buildin_setunitdata: Error in finding object BL_HOM!\n"); + return SCRIPT_CMD_FAILURE; + } + switch (type) { + case 0: hd->base_status.size = (unsigned char)value; break; + case 1: hd->homunculus.level = (unsigned short)value; break; + case 2: hd->homunculus.hp = (unsigned int)value; break; + case 3: hd->homunculus.max_hp = (unsigned int)value; break; + case 4: hd->homunculus.sp = (unsigned int)value; break; + case 5: hd->homunculus.max_sp; (unsigned int)value; break; + case 6: hd->homunculus.char_id = (unsigned int)value; break; + case 7: hd->bl.m = (short)value; break; + case 8: hd->bl.x = (short)value; break; + case 9: hd->bl.y = (short)value; break; + case 10: hd->homunculus.hunger = (short)value; break; + case 11: hd->homunculus.intimacy = (unsigned int)value; break; + case 12: hd->base_status.speed = (unsigned short)value; break; + case 13: hd->ud.dir = (unsigned char)value; break; + case 14: hd->ud.canmove_tick = value > 0 ? 1 : 0; break; + case 15: hd->base_status.str = (unsigned int)value; break; + case 16: hd->base_status.agi = (unsigned int)value; break; + case 17: hd->base_status.vit = (unsigned int)value; break; + case 18: hd->base_status.int_ = (unsigned int)value; break; + case 19: hd->base_status.dex = (unsigned int)value; break; + case 20: hd->base_status.luk = (unsigned int)value; break; + case 21: hd->ud.immune_attack = (bool)value > 0 ? 1 : 0; break; + default: + ShowError("buildin_setunitdata: Unknown data identifier %d for BL_HOM.\n", type); + return SCRIPT_CMD_FAILURE; + } + break; + + case BL_PET: + if (!pd) { + ShowWarning("buildin_setunitdata: Error in finding object BL_PET!\n"); + return SCRIPT_CMD_FAILURE; + } + switch (type) { + case 0: pd->status.size = (unsigned char)value; break; + case 1: pd->pet.level = (unsigned short)value; break; + case 2: pd->status.hp = (unsigned int)value; break; + case 3: pd->status.max_hp = (unsigned int)value; break; + case 4: pd->pet.account_id = (unsigned int)value; break; + case 5: pd->bl.m = (short)value; break; + case 6: pd->bl.x = (short)value; break; + case 7: pd->bl.y = (short)value; break; + case 8: pd->pet.hungry = (short)value; break; + case 9: pd->pet.intimate = (unsigned int)value; break; + case 10: pd->status.speed = (unsigned short)value; break; + case 11: pd->ud.dir = (unsigned char)value; break; + case 12: pd->ud.canmove_tick = value > 0 ? 1 : 0; break; + case 13: pd->status.str = (unsigned int)value; break; + case 14: pd->status.agi = (unsigned int)value; break; + case 15: pd->status.vit = (unsigned int)value; break; + case 16: pd->status.int_ = (unsigned int)value; break; + case 17: pd->status.dex = (unsigned int)value; break; + case 18: pd->status.luk = (unsigned int)value; break; + case 20: pd->ud.immune_attack = (bool)value > 0 ? 1 : 0; break; + default: + ShowError("buildin_setunitdata: Unknown data identifier %d for BL_PET.\n", type); + return SCRIPT_CMD_FAILURE; + } + break; + + case BL_MER: + if (!mc) { + ShowWarning("buildin_setunitdata: Error in finding object BL_MER!\n"); + return SCRIPT_CMD_FAILURE; + } + switch (type) { + case 0: mc->base_status.size = (unsigned char)value; break; + case 1: mc->base_status.hp = (unsigned int)value; break; + case 2: mc->base_status.max_hp = (unsigned int)value; break; + case 3: mc->mercenary.char_id = (unsigned int)value; break; + case 4: mc->bl.m = (short)value; break; + case 5: mc->bl.x = (short)value; break; + case 6: mc->bl.y = (short)value; break; + case 7: mc->mercenary.kill_count = (unsigned int)value; break; + case 8: mc->mercenary.life_time = (unsigned int)value; break; + case 9: mc->base_status.speed = (unsigned short)value; break; + case 10: mc->ud.dir = (unsigned char)value; break; + case 11: mc->ud.canmove_tick = value > 0 ? 1 : 0; break; + case 12: mc->base_status.str = (unsigned int)value; break; + case 13: mc->base_status.agi = (unsigned int)value; break; + case 14: mc->base_status.vit = (unsigned int)value; break; + case 15: mc->base_status.int_ = (unsigned int)value; break; + case 16: mc->base_status.dex = (unsigned int)value; break; + case 17: mc->base_status.luk = (unsigned int)value; break; + default: + ShowError("buildin_setunitdata: Unknown data identifier %d for BL_MER.\n", type); + return SCRIPT_CMD_FAILURE; + } + break; + + case BL_ELEM: + if (!ed) { + ShowWarning("buildin_setunitdata: Error in finding object BL_ELEM!\n"); + return SCRIPT_CMD_FAILURE; + } + switch (type) { + case 0: ed->base_status.size = (unsigned char)value; break; + case 1: ed->elemental.hp = (unsigned int)value; break; + case 2: ed->elemental.max_hp = (unsigned int)value; break; + case 3: ed->elemental.sp = (unsigned int)value; break; + case 4: ed->elemental.max_sp = (unsigned int)value; break; + case 5: ed->elemental.char_id = (unsigned int)value; break; + case 6: ed->bl.m = (short)value; break; + case 7: ed->bl.x = (short)value; break; + case 8: ed->bl.y = (short)value; break; + case 9: ed->elemental.life_time = (unsigned int)value; break; + case 10: ed->elemental.mode = (unsigned int)value; break; + case 11: ed->base_status.speed = (unsigned short)value; break; + case 12: ed->ud.dir = (unsigned char)value; break; + case 13: ed->ud.canmove_tick = value > 0 ? 1 : 0; break; + case 14: ed->base_status.str = (unsigned int)value; break; + case 15: ed->base_status.agi = (unsigned int)value; break; + case 16: ed->base_status.vit = (unsigned int)value; break; + case 17: ed->base_status.int_ = (unsigned int)value; break; + case 18: ed->base_status.dex = (unsigned int)value; break; + case 19: ed->base_status.luk = (unsigned int)value; break; + case 20: ed->ud.immune_attack = (bool)value > 0 ? 1 : 0; break; + default: + ShowError("buildin_setunitdata: Unknown data identifier %d for BL_ELEM.\n", type); + return SCRIPT_CMD_FAILURE; + } + break; + + case BL_NPC: + if (!md) { + ShowWarning("buildin_setunitdata: Error in finding object BL_NPC!\n"); + return SCRIPT_CMD_FAILURE; + } + switch (type) { + case 0: nd->class_ = (unsigned int)value; break; + case 1: nd->level = (unsigned int)value; break; + case 2: nd->status.hp = (unsigned int)value; break; + case 3: nd->status.max_hp = (unsigned int)value; break; + case 4: nd->bl.m = (short)value; break; + case 5: nd->bl.x = (short)value; break; + case 6: nd->bl.y = (short)value; break; + case 7: nd->ud.dir = (unsigned char)value; break; + case 8: nd->status.str = (unsigned int)value; break; + case 9: nd->status.agi = (unsigned int)value; break; + case 10: nd->status.vit = (unsigned int)value; break; + case 11: nd->status.int_ = (unsigned int)value; break; + case 12: nd->status.dex = (unsigned int)value; break; + case 13: nd->status.luk = (unsigned int)value; break; + default: + ShowError("buildin_setunitdata: Unknown data identifier %d for BL_NPC.\n", type); + return SCRIPT_CMD_FAILURE; + } + break; + + default: + ShowWarning("buildin_setunitdata: Unknown object type!\n"); + return SCRIPT_CMD_FAILURE; + } + + return SCRIPT_CMD_SUCCESS; +} + +/// Gets the name of a bl. +/// Supported types are [MOB|HOM|PET|NPC]. +/// MER and ELEM don't support custom names. +/// +/// getunitname ; +BUILDIN_FUNC(getunitname) +{ + struct block_list* bl = NULL; + + bl = map_id2bl(script_getnum(st, 2)); + + if (!bl) { + ShowWarning("buildin_getunitname: Error in finding object with given game ID %d!\n", script_getnum(st, 2)); + return SCRIPT_CMD_FAILURE; + } + + script_pushstrcopy(st, status_get_name(bl)); + + return SCRIPT_CMD_SUCCESS; +} + +/// Changes the name of a bl. +/// Supported types are [MOB|HOM|PET]. +/// For NPC see 'setnpcdisplay', MER and ELEM don't support custom names. +/// +/// setunitname ,; +BUILDIN_FUNC(setunitname) +{ + struct block_list* bl = NULL; + TBL_MOB* md = NULL; + TBL_HOM* hd = NULL; + TBL_PET* pd = NULL; + + bl = map_id2bl(script_getnum(st, 2)); + + if (!bl) { + ShowWarning("buildin_setunitname: Error in finding object with given game ID %d!\n", script_getnum(st, 2)); + return SCRIPT_CMD_FAILURE; + } + + switch (bl->type) { + case BL_MOB: md = map_id2md(bl->id); break; + case BL_HOM: hd = map_id2hd(bl->id); break; + case BL_PET: pd = map_id2pd(bl->id); break; + } + + switch (bl->type) { + case BL_MOB: + if (!md) { + ShowWarning("buildin_setunitname: Error in finding object BL_MOB!\n"); + return SCRIPT_CMD_FAILURE; + } + safestrncpy(md->name, script_getstr(st, 3), NAME_LENGTH); + break; + case BL_HOM: + if (!hd) { + ShowWarning("buildin_setunitname: Error in finding object BL_HOM!\n"); + return SCRIPT_CMD_FAILURE; + } + safestrncpy(hd->homunculus.name, script_getstr(st, 3), NAME_LENGTH); + break; + case BL_PET: + if (!pd) { + ShowWarning("buildin_setunitname: Error in finding object BL_PET!\n"); + return SCRIPT_CMD_FAILURE; + } + safestrncpy(pd->pet.name, script_getstr(st, 3), NAME_LENGTH); + break; + default: + ShowWarning("buildin_setunitname: Unknown object type!\n"); + return SCRIPT_CMD_FAILURE; + } + clif_charnameack(0, bl); // Send update to client. + + return SCRIPT_CMD_SUCCESS; +} + +/// Makes the unit walk to target position or map. +/// Returns if it was successful. /// /// unitwalk(,,) -> /// unitwalk(,) -> @@ -16177,41 +16728,44 @@ BUILDIN_FUNC(unitwalk) struct block_list* bl; bl = map_id2bl(script_getnum(st,2)); - if( bl == NULL ) + + if (!bl) script_pushint(st, 0); else if( script_hasdata(st,4) ) { int x = script_getnum(st,3); int y = script_getnum(st,4); - if( script_pushint(st, unit_can_reach_pos(bl,x,y,0)) ) + + if (script_pushint(st, unit_can_reach_pos(bl,x,y,0))) add_timer(gettick()+50, unit_delay_walktoxy_timer, bl->id, (x<<16)|(y&0xFFFF)); // Need timer to avoid mismatches } else { struct block_list* tbl = map_id2bl(script_getnum(st,3)); - if( tbl == NULL ) { - ShowError("script:unitwalk: bad target destination\n"); + + if (!tbl) { + ShowError("buildin_unitwalk: Bad target destination.\n"); script_pushint(st, 0); - return 1; - } - else if (script_pushint(st, unit_can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, 0, NULL, NULL))) + return SCRIPT_CMD_FAILURE; + } else if (script_pushint(st, unit_can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, 0, NULL, NULL))) add_timer(gettick()+50, unit_delay_walktobl_timer, bl->id, tbl->id); // Need timer to avoid mismatches } return SCRIPT_CMD_SUCCESS; } -/// Kills the unit +/// Kills the unit. /// /// unitkill ; BUILDIN_FUNC(unitkill) { struct block_list* bl = map_id2bl(script_getnum(st,2)); - if( bl != NULL ) + + if (bl != NULL) status_kill(bl); return SCRIPT_CMD_SUCCESS; } -/// Warps the unit to the target position in the target map -/// Returns if it was successfull +/// Warps the unit to the target position in the target map. +/// Returns if it was successful. /// /// unitwarp(,"",,) -> BUILDIN_FUNC(unitwarp) @@ -16233,12 +16787,12 @@ BUILDIN_FUNC(unitwarp) else bl = map_id2bl(unit_id); - if( strcmp(mapname,"this") == 0 ) + if (!strcmp(mapname,"this")) map_idx = bl?bl->m:-1; else map_idx = map_mapname2mapid(mapname); - if( map_idx >= 0 && bl != NULL ) + if (map_idx >= 0 && bl != NULL) script_pushint(st, unit_warp(bl,map_idx,x,y,CLR_OUTSIGHT)); else script_pushint(st, 0); @@ -16260,58 +16814,56 @@ BUILDIN_FUNC(unitattack) struct script_data* data; int actiontype = 0; - // get unit unit_bl = map_id2bl(script_getnum(st,2)); - if( unit_bl == NULL ) { + + if (!unit_bl) { script_pushint(st, 0); - return 0; + return SCRIPT_CMD_FAILURE; } data = script_getdata(st, 3); get_val(st, data); - if( data_isstring(data) ) - { + + if (data_isstring(data)) { TBL_PC* sd = map_nick2sd(conv_str(st, data)); if( sd != NULL ) target_bl = &sd->bl; } else target_bl = map_id2bl(conv_num(st, data)); - // request the attack - if( target_bl == NULL ) - { + + if (!target_bl) { script_pushint(st, 0); - return 0; + return SCRIPT_CMD_FAILURE; } - // get actiontype - if( script_hasdata(st,4) ) + if (script_hasdata(st,4)) actiontype = script_getnum(st,4); - switch( unit_bl->type ) - { - case BL_PC: - clif_parse_ActionRequest_sub(((TBL_PC *)unit_bl), actiontype > 0 ? 0x07 : 0x00, target_bl->id, gettick()); - script_pushint(st, 1); - return 0; - case BL_MOB: - ((TBL_MOB *)unit_bl)->target_id = target_bl->id; - break; - case BL_PET: - ((TBL_PET *)unit_bl)->target_id = target_bl->id; - break; - default: - ShowError("script:unitattack: unsupported source unit type %d\n", unit_bl->type); - script_pushint(st, 0); - return 1; + switch(unit_bl->type) { + case BL_PC: + clif_parse_ActionRequest_sub(((TBL_PC *)unit_bl), actiontype > 0 ? 0x07 : 0x00, target_bl->id, gettick()); + script_pushint(st, 1); + return SCRIPT_CMD_SUCCESS; + case BL_MOB: + ((TBL_MOB *)unit_bl)->target_id = target_bl->id; + break; + case BL_PET: + ((TBL_PET *)unit_bl)->target_id = target_bl->id; + break; + default: + ShowError("buildin_unitattack: Unsupported source unit type %d.\n", unit_bl->type); + script_pushint(st, 0); + return SCRIPT_CMD_FAILURE; } + script_pushint(st, unit_walktobl(unit_bl, target_bl, 65025, 2)); return SCRIPT_CMD_SUCCESS; } -/// Makes the unit stop attacking and moving +/// Makes the unit stop attacking. /// -/// unitstop ; -BUILDIN_FUNC(unitstop) +/// unitstopattack ; +BUILDIN_FUNC(unitstopattack) { int unit_id; struct block_list* bl; @@ -16319,18 +16871,38 @@ BUILDIN_FUNC(unitstop) unit_id = script_getnum(st,2); bl = map_id2bl(unit_id); - if( bl != NULL ) - { + + if (bl != NULL) { unit_stop_attack(bl); - unit_stop_walking(bl,4); - if( bl->type == BL_MOB ) + if (bl->type == BL_MOB) ((TBL_MOB*)bl)->target_id = 0; } return SCRIPT_CMD_SUCCESS; } -/// Makes the unit say the message +/// Makes the unit stop walking. +/// +/// unitstopwalk ; +BUILDIN_FUNC(unitstopwalk) +{ + int unit_id; + struct block_list* bl; + + unit_id = script_getnum(st,2); + + bl = map_id2bl(unit_id); + + if (bl != NULL) { + unit_stop_walking(bl,4); + if (bl->type == BL_MOB) + ((TBL_MOB*)bl)->target_id = 0; + } + + return SCRIPT_CMD_SUCCESS; +} + +/// Makes the unit say the given message. /// /// unittalk ,""; BUILDIN_FUNC(unittalk) @@ -16343,9 +16915,10 @@ BUILDIN_FUNC(unittalk) message = script_getstr(st, 3); bl = map_id2bl(unit_id); - if( bl != NULL ) - { + + if (bl != NULL) { struct StringBuf sbuf; + StringBuf_Init(&sbuf); StringBuf_Printf(&sbuf, "%s : %s", status_get_name(bl), message); clif_disp_overhead(bl, StringBuf_Value(&sbuf)); @@ -16355,7 +16928,7 @@ BUILDIN_FUNC(unittalk) return SCRIPT_CMD_SUCCESS; } -/// Makes the unit do an emotion +/// Makes the unit do an emotion. /// /// unitemote ,; /// @@ -16369,22 +16942,21 @@ BUILDIN_FUNC(unitemote) unit_id = script_getnum(st,2); emotion = script_getnum(st,3); bl = map_id2bl(unit_id); - if( bl != NULL ) + + if (bl != NULL) clif_emotion(bl, emotion); return SCRIPT_CMD_SUCCESS; } -/// Makes the unit cast the skill on the target or self if no target is specified +/// Makes the unit cast the skill on the target or self if no target is specified. /// -/// unitskilluseid ,,{,}; -/// unitskilluseid ,"",{,}; +/// unitskilluseid ,,{,,}; +/// unitskilluseid ,"",{,,}; BUILDIN_FUNC(unitskilluseid) { - int unit_id; - uint16 skill_id; - uint16 skill_lv; - int target_id; + int unit_id, target_id, casttime; + uint16 skill_id, skill_lv; struct block_list* bl; struct script_data *data; @@ -16394,25 +16966,23 @@ BUILDIN_FUNC(unitskilluseid) skill_id = ( data_isstring(data) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) ); skill_lv = script_getnum(st,4); target_id = ( script_hasdata(st,5) ? script_getnum(st,5) : unit_id ); - + casttime = ( script_hasdata(st,6) ? script_getnum(st,6) : 0 ); bl = map_id2bl(unit_id); - if( bl != NULL ) - unit_skilluse_id(bl, target_id, skill_id, skill_lv); + + if (bl != NULL) + unit_skilluse_id2(bl, target_id, skill_id, skill_lv, (casttime * 1000) + skill_castfix(bl, skill_id, skill_lv), skill_get_castcancel(skill_id)); return SCRIPT_CMD_SUCCESS; } /// Makes the unit cast the skill on the target position. /// -/// unitskillusepos ,,,,; -/// unitskillusepos ,"",,,; +/// unitskillusepos ,,,,{,}; +/// unitskillusepos ,"",,,{,}; BUILDIN_FUNC(unitskillusepos) { - int unit_id; - uint16 skill_id; - uint16 skill_lv; - int skill_x; - int skill_y; + int unit_id, skill_x, skill_y, casttime; + uint16 skill_id, skill_lv; struct block_list* bl; struct script_data *data; @@ -16423,10 +16993,11 @@ BUILDIN_FUNC(unitskillusepos) skill_lv = script_getnum(st,4); skill_x = script_getnum(st,5); skill_y = script_getnum(st,6); - + casttime = ( script_hasdata(st,7) ? script_getnum(st,7) : 0 ); bl = map_id2bl(unit_id); - if( bl != NULL ) - unit_skilluse_pos(bl, skill_x, skill_y, skill_id, skill_lv); + + if (bl != NULL) + unit_skilluse_pos2(bl, skill_x, skill_y, skill_id, skill_lv, (casttime * 1000) + skill_castfix(bl, skill_id, skill_lv), skill_get_castcancel(skill_id)); return SCRIPT_CMD_SUCCESS; } @@ -16715,6 +17286,8 @@ BUILDIN_FUNC(mercenary_create) contract_time = script_getnum(st,3); mercenary_create(sd, class_, contract_time); + script_pushint(st, sd->md->bl.id); + return SCRIPT_CMD_SUCCESS; } @@ -19598,15 +20171,20 @@ struct script_function buildin_func[] = { BUILDIN_DEF(pcblockmove,"ii"), // <--- [zBuffer] List of player cont commands // [zBuffer] List of mob control commands ---> + BUILDIN_DEF(getunitname,"i"), + BUILDIN_DEF(setunitname,"is"), + BUILDIN_DEF(getunitdata,"i*"), + BUILDIN_DEF(setunitdata,"iii"), BUILDIN_DEF(unitwalk,"ii?"), BUILDIN_DEF(unitkill,"i"), BUILDIN_DEF(unitwarp,"isii"), BUILDIN_DEF(unitattack,"iv?"), - BUILDIN_DEF(unitstop,"i"), + BUILDIN_DEF(unitstopattack,"i"), + BUILDIN_DEF(unitstopwalk,"i"), BUILDIN_DEF(unittalk,"is"), BUILDIN_DEF(unitemote,"ii"), - BUILDIN_DEF(unitskilluseid,"ivi?"), // originally by Qamera [Celest] - BUILDIN_DEF(unitskillusepos,"iviii"), // [Celest] + BUILDIN_DEF(unitskilluseid,"ivi??"), // originally by Qamera [Celest] + BUILDIN_DEF(unitskillusepos,"iviii?"), // [Celest] // <--- [zBuffer] List of mob control commands BUILDIN_DEF(sleep,"i"), BUILDIN_DEF(sleep2,"i"), diff --git a/src/map/status.c b/src/map/status.c index ae50b0e434..aa31d65079 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -6654,7 +6654,9 @@ const char* status_get_name(struct block_list *bl) case BL_MOB: return ((TBL_MOB*)bl)->name; case BL_PET: return ((TBL_PET*)bl)->pet.name; case BL_HOM: return ((TBL_HOM*)bl)->homunculus.name; + //case BL_MER: // They only have database names which are global, not specific to GID. case BL_NPC: return ((TBL_NPC*)bl)->name; + //case BL_ELEM: // They only have database names which are global, not specific to GID. } return "Unknown"; } diff --git a/src/map/status.h b/src/map/status.h index 51122b53ee..c896856454 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -1621,6 +1621,8 @@ enum e_mode { MD_MVP = 0x080000, MD_IGNOREMISC = 0x100000, MD_KNOCKBACK_IMMUNE = 0x200000, + MD_NORANDOM_WALK = 0x400000, + MD_NOCAST_SKILL = 0x800000, }; #define MD_MASK 0x00FFFF #define ATR_MASK 0xFF0000 diff --git a/src/map/unit.h b/src/map/unit.h index 9be19861ea..271f01e708 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -40,6 +40,7 @@ struct unit_data { unsigned int attackabletime; unsigned int canact_tick; unsigned int canmove_tick; + bool immune_attack; ///< Whether the unit is immune to attacks uint8 dir; unsigned char walk_count; unsigned char target_count;