Procházet zdrojové kódy

Follow up to 2cee5b6
* Updated setunitdata to recalculate the object's information and update the client immediately.
* For setunitdata, map name can also be passed in as a valid value instead of map ID.
* Added mapid2name script command.
* Added status_set_maxhp and status_set_maxsp functions.
* Updated documentation to reflect changes.

aleos89 před 10 roky
rodič
revize
2dc38e77ca
4 změnil soubory, kde provedl 230 přidání a 139 odebrání
  1. 27 18
      doc/script_commands.txt
  2. 147 119
      src/map/script.c
  3. 54 2
      src/map/status.c
  4. 2 0
      src/map/status.h

+ 27 - 18
doc/script_commands.txt

@@ -2872,7 +2872,7 @@ Type is the type of object to search for:
   0 - Character object
   1 - NPC object
   2 - Pet object
-  3 - Monster object
+  3 - Monster object -- See 'getunitdata' for monster.
   4 - Homunculus object
   5 - Mercenary object
   6 - Elemental object
@@ -2910,6 +2910,13 @@ Notice that NPC objects disabled with 'disablenpc' will still be located.
 
 ---------------------------------------
 
+*mapid2name(<map ID>)
+
+Returns the map name of the given map ID. Returns an empty string if given
+map ID doesn't exist.
+
+---------------------------------------
+
 *getgmlevel()
 
 This function will return the (GM) level associated with the player group to which
@@ -7064,7 +7071,7 @@ Changing a homunculus or pet name will be permanent.
 ---------------------------------------
 
 *getunitdata <GID>,<arrayname>;
-*setsetdata <GID>,<parameter>,<new value>;
+*setunitdata <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
@@ -7072,17 +7079,17 @@ 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
+	0 - size (big, small, normal)	7  - y							14 - hair style			21 - weapon			28 - LUK
+	1 - level						8  - speed						15 - hair color			22 - looking dir	29 - for slave to copy master's mode
+	2 - HP							9  - mode 						16 - head gear bottom	23 - STR			30 - immune from attacks state
+	3 - max HP						10 - special AI state	 		17 - head gear middle	24 - AGI
+	4 - master AID					11 - SC option					18 - head gear top		25 - VIT
+	5 - map ID						12 - sex						19 - cloth color		26 - INT
+	6 - x							13 - class (Monster ID, Job ID)	20 - shield				27 - DEX
 
 Parameter (indexes) for homunculi are:
 
-	0 - size (big, small, normal)	7  - map index		14 - canmove_tick	21 - immune from attacks state
+	0 - size (big, small, normal)	7  - map ID			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
@@ -7097,7 +7104,7 @@ Parameter (indexes) for pets are:
 	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 - immune from attacks state
+	5 - map ID						12 - canmove_tick	19 - immune from attacks state
 	6 - x							13 - STR
 
 Parameter (indexes) for mercenaries are:
@@ -7106,7 +7113,7 @@ Parameter (indexes) for mercenaries are:
 	1 - HP							8  - life time		15 - INT
 	2 - max HP						9  - speed 			16 - DEX
 	3 - master Character ID			10 - looking dir	17 - LUK
-	4 - map index					11 - canmove_tick	18 - immune from attacks state
+	4 - map ID						11 - canmove_tick	18 - immune from attacks state
 	5 - x							12 - STR
 	6 - y							13 - AGI
 
@@ -7118,7 +7125,7 @@ Parameter (indexes) for elementals are:
 	3 - SP							10 - mode			17 - INT
 	4 - max SP						11 - speed			18 - DEX
 	5 - master Character ID			12 - looking dir	19 - LUK
-	6 - map index					13 - canmove_tick	20 - immune from attacks state
+	6 - map ID						13 - canmove_tick	20 - immune from attacks state
 
 Parameter (indexes) for NPCs are:
 
@@ -7126,26 +7133,28 @@ Parameter (indexes) for NPCs are:
 	1 - level		8  - STR
 	2 - HP			9  - AGI
 	3 - max HP		10 - VIT
-	4 - map index	11 - INT
+	4 - map ID		11 - INT
 	5 - x			12 - DEX
 	6 - y			13 - LUK
 
-*Note: For mode, see doc/mob_db_mode_list.txt
+*Notes: For mode, see doc/mob_db_mode_list.txt
+	    For map ID, this refers to the map_data index (from src/map/map.c), not the mapindex_db index (from src/common/mapindex.c)
+	    For 'setunitdata', map name can also be passed in as a valid value instead of map ID
 
 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;
+	monster "prontera",149,190,"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.)
+	// With this data we can have the NPC display or manipulate it how we want. This does not have to be ran before 'setunitdata'.
 	getunitdata .GID,@por_arr;
 
-	// Set the max HP of the Poring to 1000 and update the current HP to match.
+	// Set the max HP of the Poring to 1000 (current HP will also get updated to 1000).
 	setunitdata .GID,3,1000;
-	setunitdata .GID,2,1000;
 
 ---------------------------------------
 \\

+ 147 - 119
src/map/script.c

@@ -13904,7 +13904,7 @@ BUILDIN_FUNC(getsavepoint)
 }
 
 /*==========================================
-  * Get position for  char/npc/pet/mob objects. Added by Lorky
+  * Get position for  char/NPC/pet/hom/merc/elem objects. Added by Lorky
   *
   *     int getMapXY(MapName$,MapX,MapY,type,[CharName$]);
   *             where type:
@@ -13915,7 +13915,7 @@ BUILDIN_FUNC(getsavepoint)
   *                                0 - Character coord
   *                                1 - NPC coord
   *                                2 - Pet coord
-  *                                3 - Mob coord (not released)
+  *                                3 - Mob coord (see 'getunitdata')
   *                                4 - Homun coord
   *                                5 - Mercenary coord
   *                                6 - Elemental coord
@@ -13986,7 +13986,7 @@ BUILDIN_FUNC(getmapxy)
 				bl = &sd->pd->bl;
 			break;
 		case 3:	//Get Mob Position
-			break; //Not supported?
+			break; //see 'getunitdata'
 		case 4:	//Get Homun Position
 			if(script_hasdata(st,6))
 				sd=map_nick2sd(script_getstr(st,6));
@@ -14066,6 +14066,23 @@ BUILDIN_FUNC(getmapxy)
 	return SCRIPT_CMD_SUCCESS;
 }
 
+/// Returns the map name of given map ID.
+///
+/// mapid2name <map ID>;
+BUILDIN_FUNC(mapid2name)
+{
+	uint16 m = script_getnum(st, 2);
+
+	if (m < 0 || m >= MAX_MAP_PER_SERVER) {
+		script_pushstr(st, "");
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	script_pushstrcopy(st, map_mapid2mapname(m));
+
+	return SCRIPT_CMD_SUCCESS;
+}
+
 /*==========================================
  * Allows player to write NPC logs (i.e. Bank NPC, etc) [Lupus]
  *------------------------------------------*/
@@ -16252,16 +16269,15 @@ BUILDIN_FUNC(getunitdata)
 			getunitdata_sub(19,md->vd->cloth_color);
 			getunitdata_sub(20,md->vd->shield);
 			getunitdata_sub(21,md->vd->weapon);
-			getunitdata_sub(22,md->vd->shield);
-			getunitdata_sub(23,md->ud.dir);
-			getunitdata_sub(24,md->status.str);
-			getunitdata_sub(25,md->status.agi);
-			getunitdata_sub(26,md->status.vit);
-			getunitdata_sub(27,md->status.int_);
-			getunitdata_sub(28,md->status.dex);
-			getunitdata_sub(29,md->status.luk);
-			getunitdata_sub(30,md->state.copy_master_mode);
-			getunitdata_sub(31,md->ud.immune_attack);
+			getunitdata_sub(22,md->ud.dir);
+			getunitdata_sub(23,md->status.str);
+			getunitdata_sub(24,md->status.agi);
+			getunitdata_sub(25,md->status.vit);
+			getunitdata_sub(26,md->status.int_);
+			getunitdata_sub(27,md->status.dex);
+			getunitdata_sub(28,md->status.luk);
+			getunitdata_sub(29,md->state.copy_master_mode);
+			getunitdata_sub(30,md->ud.immune_attack);
 			break;
 
 		case BL_HOM:
@@ -16411,6 +16427,8 @@ BUILDIN_FUNC(getunitdata)
 BUILDIN_FUNC(setunitdata)
 {
 	struct block_list* bl = NULL;
+	struct script_data* data;
+	const char *mapname = NULL;
 	TBL_MOB* md = NULL;
 	TBL_HOM* hd = NULL;
 	TBL_MER* mc = NULL;
@@ -16436,7 +16454,17 @@ BUILDIN_FUNC(setunitdata)
 	}
 
 	type = script_getnum(st, 3);
-	value = script_getnum(st, 4);
+	data = script_getdata(st, 4);
+	get_val(st, data);
+
+	if (type == 5 && data_isstring(data))
+		mapname = conv_str(st, data);
+	else if (data_isint(data))
+		value = conv_num(st, data);
+	else {
+		ShowError("buildin_setunitdata: Invalid data type for argument #3 (%d).", data->type);
+		return SCRIPT_CMD_FAILURE;
+	}
 
 	switch (bl->type) {
 	case BL_MOB:
@@ -16447,36 +16475,35 @@ BUILDIN_FUNC(setunitdata)
 		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 2: status_set_hp(bl, (unsigned int)value, 0); break;
+			case 3: status_set_maxhp(bl, (unsigned int)value, 0); 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 5: if (mapname) value = map_mapname2mapid(mapname); unit_warp(bl, (short)value, 0, 0, 3); break;
+			case 6: if (!unit_walktoxy(bl, (short)value, md->bl.y, 2)) unit_movepos(bl, (short)value, md->bl.y, 0, 0); break;
+			case 7: if (!unit_walktoxy(bl, md->bl.x, (short)value, 2)) unit_movepos(bl, md->bl.x, (short)value, 0, 0); break;
+			case 8: md->status.speed = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 9: md->status.mode = (enum e_mode)value; status_calc_bl(bl, SCB_MODE); 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;
+			case 13: status_set_viewdata(bl, (unsigned short)value); break;
+			case 14: clif_changelook(bl, LOOK_HAIR, (unsigned short)value); break;
+			case 15: clif_changelook(bl, LOOK_HAIR_COLOR, (unsigned short)value); break;
+			case 16: clif_changelook(bl, LOOK_HEAD_BOTTOM, (unsigned short)value); break;
+			case 17: clif_changelook(bl, LOOK_HEAD_MID, (unsigned short)value); break;
+			case 18: clif_changelook(bl, LOOK_HEAD_TOP, (unsigned short)value); break;
+			case 19: clif_changelook(bl, LOOK_CLOTHES_COLOR, (unsigned short)value); break;
+			case 20: clif_changelook(bl, LOOK_SHIELD, (unsigned short)value); break;
+			case 21: clif_changelook(bl, LOOK_WEAPON, (unsigned short)value); break;
+			case 22: unit_setdir(bl, (uint8)value); break;
+			case 23: md->status.str = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 24: md->status.agi = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 25: md->status.vit = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 26: md->status.int_ = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 27: md->status.dex = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 28: md->status.luk = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 29: md->state.copy_master_mode = value > 0 ? 1 : 0; status_calc_bl(bl, SCB_MODE); break;
+			case 30: 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;
@@ -16491,25 +16518,25 @@ BUILDIN_FUNC(setunitdata)
 		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 2: status_set_hp(bl, (unsigned int)value, 0); break;
+			case 3: status_set_maxhp(bl, (unsigned int)value, 0); break;
+			case 4: status_set_sp(bl, (unsigned int)value, 0); break;
+			case 5: status_set_maxsp(bl, (unsigned int)value, 0); break;
+			case 6: hd->homunculus.char_id = (uint32)value; break;
+			case 7: if (mapname) value = map_mapname2mapid(mapname); unit_warp(bl, (short)value, 0, 0, 3); break;
+			case 8: if (!unit_walktoxy(bl, (short)value, hd->bl.y, 2)) unit_movepos(bl, (short)value, hd->bl.y, 0, 0); break;
+			case 9: if (!unit_walktoxy(bl, hd->bl.x, (short)value, 2)) unit_movepos(bl, hd->bl.x, (short)value, 0, 0); break;
+			case 10: hd->homunculus.hunger = (short)value; clif_send_homdata(map_charid2sd(hd->homunculus.char_id), SP_HUNGRY, hd->homunculus.hunger); break;
+			case 11: hom_increase_intimacy(hd, (unsigned int)value); clif_send_homdata(map_charid2sd(hd->homunculus.char_id), SP_INTIMATE, hd->homunculus.intimacy / 100); break;
+			case 12: hd->base_status.speed = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 13: unit_setdir(bl, (uint8)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 15: hd->base_status.str = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 16: hd->base_status.agi = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 17: hd->base_status.vit = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 18: hd->base_status.int_ = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 19: hd->base_status.dex = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 20: hd->base_status.luk = (unsigned short)value; status_calc_bl(bl, SCB_ALL); 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);
@@ -16525,23 +16552,23 @@ BUILDIN_FUNC(setunitdata)
 		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 2: status_set_hp(bl, (unsigned int)value, 0); break;
+			case 3: status_set_maxhp(bl, (unsigned int)value, 0); 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 5: if (mapname) value = map_mapname2mapid(mapname); unit_warp(bl, (short)value, 0, 0, 3); break;
+			case 6: if (!unit_walktoxy(bl, (short)value, pd->bl.y, 2)) unit_movepos(bl, (short)value, md->bl.y, 0, 0); break;
+			case 7: if (!unit_walktoxy(bl, pd->bl.x, (short)value, 2)) unit_movepos(bl, pd->bl.x, (short)value, 0, 0); break;
+			case 8: pd->pet.hungry = (short)value; clif_send_petdata(map_id2sd(pd->pet.account_id), pd, 2, pd->pet.hungry); break;
+			case 9: pet_set_intimate(pd, (unsigned int)value); clif_send_petdata(map_id2sd(pd->pet.account_id), pd, 1, pd->pet.intimate); break;
+			case 10: pd->status.speed = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 11: unit_setdir(bl, (uint8)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 13: pd->status.str = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 14: pd->status.agi = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 15: pd->status.vit = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 16: pd->status.int_ = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 17: pd->status.dex = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 18: pd->status.luk = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
 			case 19: pd->ud.immune_attack = (bool)value > 0 ? 1 : 0; break;
 			default:
 				ShowError("buildin_setunitdata: Unknown data identifier %d for BL_PET.\n", type);
@@ -16556,23 +16583,23 @@ BUILDIN_FUNC(setunitdata)
 		}
 		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 1: status_set_hp(bl, (unsigned int)value, 0); break;
+			case 2: status_set_maxhp(bl, (unsigned int)value, 0); break;
+			case 3: mc->mercenary.char_id = (uint32)value; break;
+			case 4: if (mapname) value = map_mapname2mapid(mapname); unit_warp(bl, (short)value, 0, 0, 3); break;
+			case 5: if (!unit_walktoxy(bl, (short)value, mc->bl.y, 2)) unit_movepos(bl, (short)value, mc->bl.y, 0, 0); break;
+			case 6: if (!unit_walktoxy(bl, mc->bl.x, (short)value, 2)) unit_movepos(bl, mc->bl.x, (short)value, 0, 0); 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 9: mc->base_status.speed = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 10: unit_setdir(bl, (uint8)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;
+			case 12: mc->base_status.str = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 13: mc->base_status.agi = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 14: mc->base_status.vit = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 15: mc->base_status.int_ = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 16: mc->base_status.dex = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 17: mc->base_status.luk = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
 			case 18: mc->ud.immune_attack = (bool)value > 0 ? 1 : 0; break;
 			default:
 				ShowError("buildin_setunitdata: Unknown data identifier %d for BL_MER.\n", type);
@@ -16587,25 +16614,25 @@ BUILDIN_FUNC(setunitdata)
 		}
 		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 1: status_set_hp(bl, (unsigned int)value, 0); break;
+			case 2: status_set_maxhp(bl, (unsigned int)value, 0); break;
+			case 3: status_set_sp(bl, (unsigned int)value, 0); break;
+			case 4: status_set_maxsp(bl, (unsigned int)value, 0); break;
+			case 5: ed->elemental.char_id = (uint32)value; break;
+			case 6: if (mapname) value = map_mapname2mapid(mapname); unit_warp(bl, (short)value, 0, 0, 3); break;
+			case 7: if (!unit_walktoxy(bl, (short)value, ed->bl.y, 2)) unit_movepos(bl, (short)value, ed->bl.y, 0, 0); break;
+			case 8: if (!unit_walktoxy(bl, ed->bl.x, (short)value, 2)) unit_movepos(bl, ed->bl.x, (short)value, 0, 0); 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 10: ed->elemental.mode = (unsigned int)value; status_calc_bl(bl, SCB_MODE); break;
+			case 11: ed->base_status.speed = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 12: unit_setdir(bl, (uint8)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 14: ed->base_status.str = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 15: ed->base_status.agi = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 16: ed->base_status.vit = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 17: ed->base_status.int_ = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 18: ed->base_status.dex = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 19: ed->base_status.luk = (unsigned short)value; status_calc_bl(bl, SCB_ALL); 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);
@@ -16619,20 +16646,20 @@ BUILDIN_FUNC(setunitdata)
 			return SCRIPT_CMD_FAILURE;
 		}
 		switch (type) {
-			case 0: nd->class_ = (unsigned int)value; break;
+			case 0: status_set_viewdata(bl, (unsigned short)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;
+			case 2: status_set_hp(bl, (unsigned int)value, 0); break;
+			case 3: status_set_maxhp(bl, (unsigned int)value, 0); break;
+			case 4: if (mapname) value = map_mapname2mapid(mapname); unit_warp(bl, (short)value, 0, 0, 3); break;
+			case 5: if (!unit_walktoxy(bl, (short)value, nd->bl.y, 2)) unit_movepos(bl, (short)value, nd->bl.x, 0, 0); break;
+			case 6: if (!unit_walktoxy(bl, nd->bl.x, (short)value, 2)) unit_movepos(bl, nd->bl.x, (short)value, 0, 0); break;
+			case 7: unit_setdir(bl, (uint8)value); break;
+			case 8: nd->status.str = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 9: nd->status.agi = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 10: nd->status.vit = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 11: nd->status.int_ = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 12: nd->status.dex = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
+			case 13: nd->status.luk = (unsigned short)value; status_calc_bl(bl, SCB_ALL); break;
 			default:
 				ShowError("buildin_setunitdata: Unknown data identifier %d for BL_NPC.\n", type);
 				return SCRIPT_CMD_FAILURE;
@@ -16938,7 +16965,7 @@ BUILDIN_FUNC(unittalk)
 ///
 /// unitemote <unit_id>,<emotion>;
 ///
-/// @see e_* in const.txt
+/// @see e_* in db/const.txt
 BUILDIN_FUNC(unitemote)
 {
 	int unit_id;
@@ -17008,7 +17035,7 @@ BUILDIN_FUNC(unitskillusepos)
 	return SCRIPT_CMD_SUCCESS;
 }
 
-// <--- [zBuffer] List of mob control commands
+// <--- [zBuffer] List of unit control commands
 
 /// Pauses the execution of the script, detaching the player
 ///
@@ -20085,6 +20112,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(npcwalkto,"ii"), // [Valaris]
 	BUILDIN_DEF(npcstop,""), // [Valaris]
 	BUILDIN_DEF(getmapxy,"rrri?"),	//by Lorky [Lupus]
+	BUILDIN_DEF(mapid2name,"i"),
 	BUILDIN_DEF(checkoption1,"i"),
 	BUILDIN_DEF(checkoption2,"i"),
 	BUILDIN_DEF(guildgetexp,"i"),

+ 54 - 2
src/map/status.c

@@ -1275,8 +1275,8 @@ static inline void status_cpy(struct status_data* a, const struct status_data* b
 
 /**
  * Sets HP to a given value
- * Will always succeed (overrides heal impedement statuses) but can't kill an object
- * @param bl: Object whose HP will be set [PC|MOB|HOM|MER|ELEM]
+ * Will always succeed (overrides heal impediment statuses) but can't kill an object
+ * @param bl: Object whose HP will be set [PC|MOB|HOM|MER|ELEM|NPC]
  * @param hp: What the HP is to be set as
  * @param flag: Used in case final value is higher than current
  *		Use 2 to display healing effect
@@ -1297,6 +1297,32 @@ int status_set_hp(struct block_list *bl, unsigned int hp, int flag)
 	return status_zap(bl, status->hp - hp, 0);
 }
 
+/**
+ * Sets Max HP to a given value
+ * @param bl: Object whose Max HP will be set [PC|MOB|HOM|MER|ELEM|NPC]
+ * @param maxhp: What the Max HP is to be set as
+ * @param flag: Used in case final value is higher than current
+ *		Use 2 to display healing effect
+ * @return heal or zapped HP if valid
+ */
+int status_set_maxhp(struct block_list *bl, unsigned int maxhp, int flag)
+{
+	struct status_data *status;
+	if (maxhp < 1) return 0;
+	status = status_get_status_data(bl);
+	if (status == &dummy_status)
+		return 0;
+
+	if (maxhp == status->max_hp) return 0;
+	if (maxhp > status->max_hp) {
+		status_heal(bl, maxhp - status->max_hp, 0, 1|flag);
+	} else
+		status_zap(bl, status->max_hp - maxhp, 0);
+
+	status->max_hp = maxhp;
+	return maxhp;
+}
+
 /**
  * Sets SP to a given value
  * @param bl: Object whose SP will be set [PC|HOM|MER|ELEM]
@@ -1320,6 +1346,32 @@ int status_set_sp(struct block_list *bl, unsigned int sp, int flag)
 	return status_zap(bl, 0, status->sp - sp);
 }
 
+/**
+ * Sets Max SP to a given value
+ * @param bl: Object whose Max SP will be set [PC|HOM|MER|ELEM]
+ * @param maxsp: What the Max SP is to be set as
+ * @param flag: Used in case final value is higher than current
+ *		Use 2 to display healing effect
+ * @return heal or zapped HP if valid
+ */
+int status_set_maxsp(struct block_list *bl, unsigned int maxsp, int flag)
+{
+	struct status_data *status;
+	if (maxsp < 1) return 0;
+	status = status_get_status_data(bl);
+	if (status == &dummy_status)
+		return 0;
+
+	if (maxsp == status->max_sp) return 0;
+	if (maxsp > status->max_sp) {
+		status_heal(bl, maxsp - status->max_sp, 0, 1|flag);
+	} else
+		status_zap(bl, status->max_sp - maxsp, 0);
+
+	status->max_sp = maxsp;
+	return maxsp;
+}
+
 /**
  * Takes HP/SP from an Object
  * @param bl: Object who will have HP/SP taken [PC|MOB|HOM|MER|ELEM]

+ 2 - 0
src/map/status.h

@@ -2003,7 +2003,9 @@ int status_percent_change(struct block_list *src, struct block_list *target, int
 #define status_kill(bl) status_percent_damage(NULL, bl, 100, 0, true)
 //Used to set the hp/sp of an object to an absolute value (can't kill)
 int status_set_hp(struct block_list *bl, unsigned int hp, int flag);
+int status_set_maxhp(struct block_list *bl, unsigned int hp, int flag);
 int status_set_sp(struct block_list *bl, unsigned int sp, int flag);
+int status_set_maxsp(struct block_list *bl, unsigned int hp, int flag);
 int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int flag);
 int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp);