Implemented Basic Unit Controller Script Commands

* Added getunitname, setunitname, getunitdata, and setunitdata script commands.
- getunitdata and setunitdata are open to suggestions for more values.
* Split unitstop to unitstopattack and unitstopwalk.
* Expanded unitskilluseid and unitskillusepos to be able to adjust casttime of skill.
* Added two new monster modes: MD_NORANDOM_WALK and MD_NOCAST_SKILL.
* The areamonster script command now saves spawned monster game IDs in an array called $@mobid[].
* Adjusted other monster spawning script commands to return game ID.
* Updated documentation to reflect changes.
This commit is contained in:
aleos89 2015-03-19 20:47:57 -04:00
parent e3adcbda3b
commit 2cee5b6ff1
11 changed files with 841 additions and 122 deletions

View File

@ -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

View File

@ -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:
<Normal NPC object definition. Let's assume you called him NPCNAME.>
@ -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 <GID>;
*unitstopattack <GID>;
This command will make a <GID> stop attacking and moving.
This command will make a <GID> stop attacking.
---------------------------------------
*unitstopwalk <GID>;
This command will make a <GID> stop moving.
---------------------------------------
@ -7018,16 +7029,123 @@ For a full list of emotion numbers, see 'db/const.txt' under 'e_'.
---------------------------------------
*unitskilluseid <GID>,<skill id>,<skill lvl>{,<target id>};
*unitskilluseid <GID>,"<skill name>",<skill lvl>{,<target id>};
*unitskillusepos <GID>,<skill id>,<skill lvl>,<x>,<y>;
*unitskillusepos <GID>,"<skill name>",<skill lvl>,<x>,<y>;
*unitskilluseid <GID>,<skill id>,<skill lvl>{,<target id>,<casttime>};
*unitskilluseid <GID>,"<skill name>",<skill lvl>{,<target id>,<casttime>};
*unitskillusepos <GID>,<skill id>,<skill lvl>,<x>,<y>{,<casttime>};
*unitskillusepos <GID>,"<skill name>",<skill lvl>,<x>,<y>{,<casttime>};
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 <GID>;
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 <GID>,"<new name>";
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 <GID>,<arrayname>;
*setsetdata <GID>,<parameter>,<new value>;
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 <hp>,<sp>;
@ -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.

View File

@ -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:

View File

@ -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);

View File

@ -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 );

View File

@ -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)

View File

@ -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!

View File

@ -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 "<map name>",<x>,<y>,"<name to show>",<mob id>,<amount>{,"<event label>",<size>,<ai>};
@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<amount; i++){ //not optimised
for(i = 0; i < amount; i++) { //not optimised
int mobid = mob_once_spawn(sd, m, x, y, str, class_, 1, event, size, ai);
if(mobid) mapreg_setreg(reference_uid(add_str("$@mobid"), i),mobid);
if (mobid)
mapreg_setreg(reference_uid(add_str("$@mobid"), i), mobid);
}
return SCRIPT_CMD_SUCCESS;
}
/*==========================================
* Request List of Monster Drops
*------------------------------------------*/
@ -9460,8 +9462,10 @@ BUILDIN_FUNC(getmobdrops)
return SCRIPT_CMD_SUCCESS;
}
/*==========================================
* Same as monster but randomize location in x0,x1,y0,y1 area
* Spawn a monster in a random location
* in x0,x1,y0,y1 area.
*------------------------------------------*/
BUILDIN_FUNC(areamonster)
{
@ -9479,6 +9483,7 @@ BUILDIN_FUNC(areamonster)
struct map_session_data* sd;
int16 m;
int i;
if (script_hasdata(st,10)) {
event = script_getstr(st, 10);
@ -9508,9 +9513,16 @@ BUILDIN_FUNC(areamonster)
else
m = map_mapname2mapid(mapn);
mob_once_spawn_area(sd, m, x0, y0, x1, y1, str, class_, amount, event, size, ai);
for(i = 0; i < amount; i++) { //not optimised
int mobid = mob_once_spawn_area(sd, m, x0, y0, x1, y1, str, class_, 1, event, size, ai);
if (mobid)
mapreg_setreg(reference_uid(add_str("$@mobid"), i), mobid);
}
return SCRIPT_CMD_SUCCESS;
}
/*==========================================
* KillMonster subcheck, verify if mob to kill ain't got an even to handle, could be force kill by allflag
*------------------------------------------*/
@ -13550,6 +13562,7 @@ BUILDIN_FUNC(recovery)
script_pushint(st,1); //Successfully executed without errors
return SCRIPT_CMD_SUCCESS;
}
/*==========================================
* Get your pet info: getpetinfo(n)
* n -> 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 <unit id>,<arrayname>;
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 <unit id>,<type>,<value>;
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 <unit id>;
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 <unit id>,<name>;
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(<unit_id>,<x>,<y>) -> <bool>
/// unitwalk(<unit_id>,<target_id>) -> <bool>
@ -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 <unit_id>;
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(<unit_id>,"<map name>",<x>,<y>) -> <bool>
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,39 +16814,36 @@ 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 )
{
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;
return SCRIPT_CMD_SUCCESS;
case BL_MOB:
((TBL_MOB *)unit_bl)->target_id = target_bl->id;
break;
@ -16300,18 +16851,19 @@ BUILDIN_FUNC(unitattack)
((TBL_PET *)unit_bl)->target_id = target_bl->id;
break;
default:
ShowError("script:unitattack: unsupported source unit type %d\n", unit_bl->type);
ShowError("buildin_unitattack: Unsupported source unit type %d.\n", unit_bl->type);
script_pushint(st, 0);
return 1;
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 <unit_id>;
BUILDIN_FUNC(unitstop)
/// unitstopattack <unit_id>;
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 <unit_id>;
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 <unit_id>,"<message>";
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 <unit_id>,<emotion>;
///
@ -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 <unit_id>,<skill_id>,<skill_lv>{,<target_id>};
/// unitskilluseid <unit_id>,"<skill name>",<skill_lv>{,<target_id>};
/// unitskilluseid <unit_id>,<skill_id>,<skill_lv>{,<target_id>,<casttime>};
/// unitskilluseid <unit_id>,"<skill name>",<skill_lv>{,<target_id>,<casttime>};
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 <unit_id>,<skill_id>,<skill_lv>,<target_x>,<target_y>;
/// unitskillusepos <unit_id>,"<skill name>",<skill_lv>,<target_x>,<target_y>;
/// unitskillusepos <unit_id>,<skill_id>,<skill_lv>,<target_x>,<target_y>{,<casttime>};
/// unitskillusepos <unit_id>,"<skill name>",<skill_lv>,<target_x>,<target_y>{,<casttime>};
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"),

View File

@ -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";
}

View File

@ -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

View File

@ -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;