Browse Source

Updates to the Adoption System
* Part of #3074.
* Adds script command unadopt and atcommand unadopt to allow babies to leave their parents.
* Includes an independence flag which converts the baby to a normal class.
* Adds support for any class base level 50 or less to be adopted (in renewal mode).

Aleos 5 years ago
parent
commit
dc587df982
7 changed files with 245 additions and 25 deletions
  1. 6 0
      conf/atcommands.yml
  2. 7 0
      conf/msg_conf/map_msg.conf
  3. 19 1
      doc/script_commands.txt
  4. 50 4
      src/map/atcommand.cpp
  5. 80 3
      src/map/pc.cpp
  6. 19 11
      src/map/pc.hpp
  7. 64 6
      src/map/script.cpp

+ 6 - 0
conf/atcommands.yml

@@ -964,6 +964,12 @@ Body:
   - Command: reloadnpcfile
     Aliases:
       - reloadnpc
+  - Command: adopt
+    Help: |
+      Adopt a character.
+  - Command: unadopt
+    Help: |
+      Disown a character. Independence flag will make the baby a normal class.
 
 Footer:
   Imports:

+ 7 - 0
conf/msg_conf/map_msg.conf

@@ -1706,5 +1706,12 @@
 1503: You've entered a PK Zone.
 1504: You've entered a PK Zone (safe until level %d).
 
+// More Adoption
+1505: The Baby is not level 50 or lower.
+1506: Baby has been disowned.
+1507: Baby is not adopted.
+1508: A Parent is not the father or mother of the Baby.
+1509: Usage: <char name> <independent_baby>
+
 //Custom translations
 import: conf/msg_conf/import/map_msg_eng_conf.txt

+ 19 - 1
doc/script_commands.txt

@@ -6095,12 +6095,30 @@ Return values:
  ADOPT_ALREADY_ADOPTED - Character is already adopted.
  ADOPT_MARRIED_AND_PARTY - Parents need to be married and in a party with the baby.
  ADOPT_EQUIP_RINGS - Parents need wedding rings equipped.
- ADOPT_NOT_NOVICE - Baby is not a Novice.
+ ADOPT_NOT_NOVICE - Baby is not a Novice. In RENEWAL this has been changed to any class less that is base level 50 or lower.
  ADOPT_CHARACTER_NOT_FOUND - A parent or Baby was not found.
  ADOPT_MORE_CHILDREN - You cannot adopt more than 1 child. (client message)
  ADOPT_LEVEL_70 - Parents need to be at least level 70 in order to adopt someone. (client message)
  ADOPT_MARRIED - You cannot adopt a married person. (client message)
 
+---------------------------------------
+
+*unadopt("<parent_name>","<baby_name>"{,<independent_baby>});
+*unadopt(<parent_id>,<baby_id>{,<independent_baby>});
+
+This function will remove an adoption to the specified baby character. The parent
+value can be either parent. Both parents and the baby need to be online in order
+for adoption removal to work.
+
+The <independent_baby> option allows the baby to be converted to a normal class. This option
+is false by default.
+
+Return values:
+ UNADOPT_ALLOWED - Baby is no longer adopted.
+ UNADOPT_CHARACTER_NOT_FOUND - A parent or Baby was not found.
+ UNADOPT_NOT_ADOPTED - The Baby is not adopted.
+ UNADOPT_NOT_CHILD - A Parent is not the father or mother of the Baby.
+
 ---------------------------------------
 //
 4,3.- End of marriage-related commands

+ 50 - 4
src/map/atcommand.cpp

@@ -10051,7 +10051,6 @@ ACMD_FUNC(clonestat) {
 ACMD_FUNC(adopt)
 {
 	TBL_PC *b_sd;
-	enum adopt_responses response;
 
 	nullpo_retr(-1, sd);
 
@@ -10064,12 +10063,12 @@ ACMD_FUNC(adopt)
 		return -1;
 	}
 
-	if ((b_sd = map_nick2sd(atcmd_player_name,false)) == NULL) {
+	if ((b_sd = map_nick2sd(atcmd_player_name,false)) == nullptr) {
 		clif_displaymessage(fd, msg_txt(sd, 3)); // Character not found.
 		return -1;
 	}
 
-	response = pc_try_adopt(sd, map_charid2sd(sd->status.partner_id), b_sd);
+	e_adopt_responses response = pc_try_adopt(sd, map_charid2sd(sd->status.partner_id), b_sd);
 
 	if (response == ADOPT_ALLOWED) {
 		TBL_PC *p_sd = map_charid2sd(sd->status.partner_id);
@@ -10079,8 +10078,54 @@ ACMD_FUNC(adopt)
 		return 0;
 	}
 
-	if (response < ADOPT_MORE_CHILDREN) // No displaymessage for client-type responses
+	if (response < ADOPT_MORE_CHILDREN) { // No displaymessage for client-type responses
+#ifdef RENEWAL
+		if (response == ADOPT_NOT_NOVICE)
+			clif_displaymessage(fd, msg_txt(sd, 1505));
+		else
+#endif
 		clif_displaymessage(fd, msg_txt(sd, 744 + response - 1));
+	}
+	return -1;
+}
+
+/**
+ * Remove an adopted character.
+ * Usage: @unadopt <char name> <independent_baby>
+ */
+ACMD_FUNC(unadopt)
+{
+	TBL_PC *b_sd;
+
+	nullpo_retr(-1, sd);
+
+	memset(atcmd_output, '\0', sizeof(atcmd_output));
+	memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
+
+	uint8 independent_baby = 0;
+
+	if (!message || !*message || sscanf(message, "%23s %1hhu", atcmd_player_name, &independent_baby) < 1) {
+		sprintf(atcmd_output, msg_txt(sd, 1509), command); // Usage: <char name> <independent_baby>
+		clif_displaymessage(fd, atcmd_output);
+		return -1;
+	}
+
+	if ((b_sd = map_nick2sd(atcmd_player_name,false)) == nullptr) {
+		clif_displaymessage(fd, msg_txt(sd, 3)); // Character not found.
+		return -1;
+	}
+
+	e_unadopt_responses response = pc_unadopt(sd, map_charid2sd(sd->status.partner_id), b_sd, independent_baby != 0);
+
+	if (response == UNADOPT_ALLOWED) {
+		clif_displaymessage(fd, msg_txt(sd, 1506)); // Baby has been disowned.
+		return 0;
+	}
+
+	if (response == UNADOPT_CHARACTER_NOT_FOUND)
+		clif_displaymessage(fd, msg_txt(sd, 748)); // A Parent or Baby was not found.
+	else
+		clif_displaymessage(fd, msg_txt(sd, 1507 + response - 1));
 	return -1;
 }
 
@@ -10427,6 +10472,7 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(clonestat),
 		ACMD_DEF(bodystyle),
 		ACMD_DEF(adopt),
+		ACMD_DEF2("unadopt", adopt),
 		ACMD_DEF(agitstart3),
 		ACMD_DEF(agitend3),
 		ACMD_DEFR(limitedsale, ATCMD_NOCONSOLE|ATCMD_NOAUTOTRADE),

+ 80 - 3
src/map/pc.cpp

@@ -1049,7 +1049,7 @@ bool pc_isequipped(struct map_session_data *sd, unsigned short nameid)
  *         ADOPT_LEVEL_70 - Parents need to be level 70+ (client message)
  *         ADOPT_MARRIED - Cannot adopt a married person (client message)
  */
-enum adopt_responses pc_try_adopt(struct map_session_data *p1_sd, struct map_session_data *p2_sd, struct map_session_data *b_sd)
+e_adopt_responses pc_try_adopt(struct map_session_data *p1_sd, struct map_session_data *p2_sd, struct map_session_data *b_sd)
 {
 	if( !p1_sd || !p2_sd || !b_sd )
 		return ADOPT_CHARACTER_NOT_FOUND;
@@ -1090,7 +1090,11 @@ enum adopt_responses pc_try_adopt(struct map_session_data *p1_sd, struct map_ses
 		return ADOPT_MARRIED;
 	}
 
-	if( !( ( b_sd->status.class_ >= JOB_NOVICE && b_sd->status.class_ <= JOB_THIEF ) || b_sd->status.class_ == JOB_SUPER_NOVICE || b_sd->status.class_ == JOB_SUPER_NOVICE_E ) )
+#ifdef RENEWAL
+	if (b_sd->status.base_level < 51)
+#else
+	if (!((b_sd->status.class_ >= JOB_NOVICE && b_sd->status.class_ <= JOB_THIEF) || b_sd->status.class_ == JOB_SUPER_NOVICE || b_sd->status.class_ == JOB_SUPER_NOVICE_E))
+#endif
 		return ADOPT_NOT_NOVICE;
 
 	return ADOPT_ALLOWED;
@@ -1147,7 +1151,80 @@ bool pc_adoption(struct map_session_data *p1_sd, struct map_session_data *p2_sd,
 
 	return false; // Job Change Fail
 }
- 
+
+/**
+ * Check unadoption rules and remove adoption
+ * @param p1_sd: Player 1
+ * @param p2_sd: Player 2
+ * @param b_sd: Player that will be unadopted
+ * @param independent_baby: If the baby becomes a normal class
+ * @return see pc.hpp::e_unadopt_responses
+ */
+e_unadopt_responses pc_unadopt(struct map_session_data *p1_sd, struct map_session_data *p2_sd, struct map_session_data *b_sd, bool independent_baby) {
+	if (!p1_sd || !p2_sd || !b_sd)
+		return UNADOPT_CHARACTER_NOT_FOUND;
+
+	if (!b_sd->status.father || !b_sd->status.mother)
+		return UNADOPT_NOT_ADOPTED;
+
+	if (p1_sd->status.child != b_sd->status.char_id && p2_sd->status.child != b_sd->status.char_id)
+		return UNADOPT_NOT_CHILD;
+
+	// Baby is separated from parents by independence option (Becomes a normal class)
+	if (independent_baby) {
+		int32 joblevel = b_sd->status.job_level, job = pc_mapid2jobid(b_sd->class_ | ~JOBL_BABY, b_sd->status.sex);
+		uint32 jobexp = b_sd->status.job_exp;
+
+		if (job == -1 || !pc_jobchange(b_sd, job, 0))
+			return UNADOPT_CHARACTER_NOT_FOUND;
+	}
+
+	// Remove Baby/Parent status
+	p1_sd->status.child = 0;
+	p2_sd->status.child = 0;
+	b_sd->status.father = 0;
+	b_sd->status.mother = 0;
+
+	uint16 sk_idx;
+
+	// Remove Baby Skills
+	if ((sk_idx = skill_get_index(WE_BABY)) > 0 && pc_checkskill(b_sd, WE_BABY) > 0) {
+		b_sd->status.skill[sk_idx].lv = 0;
+		b_sd->status.skill[sk_idx].flag = SKILL_FLAG_TEMPORARY;
+		clif_deleteskill(b_sd, WE_BABY);
+	}
+	if ((sk_idx = skill_get_index(WE_CALLPARENT)) > 0 && pc_checkskill(b_sd, WE_CALLPARENT) > 0) {
+		b_sd->status.skill[sk_idx].lv = 0;
+		b_sd->status.skill[sk_idx].flag = SKILL_FLAG_TEMPORARY;
+		clif_deleteskill(b_sd, WE_CALLPARENT);
+	}
+	if ((sk_idx = skill_get_index(WE_CHEERUP)) > 0 && pc_checkskill(b_sd, WE_CHEERUP) > 0) {
+		b_sd->status.skill[sk_idx].lv = 0;
+		b_sd->status.skill[sk_idx].flag = SKILL_FLAG_TEMPORARY;
+		clif_deleteskill(b_sd, WE_CHEERUP);
+	}
+
+	// Remove Parents Skills
+	if ((sk_idx = skill_get_index(WE_CALLBABY)) > 0) {
+		if (pc_checkskill(p1_sd, WE_CALLBABY) > 0) {
+			p1_sd->status.skill[sk_idx].lv = 0;
+			p1_sd->status.skill[sk_idx].flag = SKILL_FLAG_TEMPORARY;
+			clif_deleteskill(b_sd, WE_CALLBABY);
+		}
+		if (pc_checkskill(p2_sd, WE_CALLBABY) > 0) {
+			p1_sd->status.skill[sk_idx].lv = 0;
+			p1_sd->status.skill[sk_idx].flag = SKILL_FLAG_TEMPORARY;
+			clif_deleteskill(b_sd, WE_CALLBABY);
+		}
+	}
+
+	chrif_save(p1_sd, CSAVE_NORMAL);
+	chrif_save(p2_sd, CSAVE_NORMAL);
+	chrif_save(b_sd, CSAVE_NORMAL);
+
+	return UNADOPT_ALLOWED;
+}
+
 /*==========================================
  * Check if player can use/equip selected item. Used by pc_isUseitem and pc_isequip
    Returns:

+ 19 - 11
src/map/pc.hpp

@@ -836,16 +836,23 @@ enum idletime_option {
 	IDLE_ATCOMMAND     = 0x200,
 };
 
-enum adopt_responses {
-	ADOPT_ALLOWED = 0,
-	ADOPT_ALREADY_ADOPTED,
-	ADOPT_MARRIED_AND_PARTY,
-	ADOPT_EQUIP_RINGS,
-	ADOPT_NOT_NOVICE,
-	ADOPT_CHARACTER_NOT_FOUND,
-	ADOPT_MORE_CHILDREN,
-	ADOPT_LEVEL_70,
-	ADOPT_MARRIED,
+enum e_adopt_responses : uint8 {
+	ADOPT_ALLOWED = 0, ///< Baby can be adopted
+	ADOPT_ALREADY_ADOPTED, ///< Player is already adopted
+	ADOPT_MARRIED_AND_PARTY, ///< Parents need to be married and in a party
+	ADOPT_EQUIP_RINGS, ///< Parents need their wedding rings equipped
+	ADOPT_NOT_NOVICE, ///< Baby is not a Novice
+	ADOPT_CHARACTER_NOT_FOUND, ///< Baby or Parent not found
+	ADOPT_MORE_CHILDREN, ///< Cannot adopt more than 1 baby (client message)
+	ADOPT_LEVEL_70, ///< Parents need to be level 70 or higher (client message)
+	ADOPT_MARRIED, ///< Parents need to be married (client message)
+};
+
+enum e_unadopt_responses : uint8 {
+	UNADOPT_ALLOWED = 0, ///< Baby can be unadopted
+	UNADOPT_CHARACTER_NOT_FOUND, ///< Baby or Parent not found
+	UNADOPT_NOT_ADOPTED, ///< Baby is not adopted
+	UNADOPT_NOT_CHILD, ///< Neither parent is the father/mother
 };
 
 enum item_check {
@@ -1120,8 +1127,9 @@ bool pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem);
 bool pc_dropitem(struct map_session_data *sd,int n,int amount);
 
 bool pc_isequipped(struct map_session_data *sd, unsigned short nameid);
-enum adopt_responses pc_try_adopt(struct map_session_data *p1_sd, struct map_session_data *p2_sd, struct map_session_data *b_sd);
+e_adopt_responses pc_try_adopt(struct map_session_data *p1_sd, struct map_session_data *p2_sd, struct map_session_data *b_sd);
 bool pc_adoption(struct map_session_data *p1_sd, struct map_session_data *p2_sd, struct map_session_data *b_sd);
+e_unadopt_responses pc_unadopt(struct map_session_data *p1_sd, struct map_session_data *p2_sd, struct map_session_data *b_sd, bool independent_baby);
 
 void pc_updateweightstatus(struct map_session_data *sd);
 

+ 64 - 6
src/map/script.cpp

@@ -22729,13 +22729,12 @@ BUILDIN_FUNC(navigateto){
 BUILDIN_FUNC(adopt)
 {
 	TBL_PC *sd, *b_sd;
-	enum adopt_responses response;
 
 	if (script_isstring(st, 2)) {
 		const char *name = script_getstr(st, 2);
 
 		sd = map_nick2sd(name,false);
-		if (sd == NULL) {
+		if (sd == nullptr) {
 			ShowError("buildin_adopt: Non-existant parent character %s requested.\n", name);
 			return SCRIPT_CMD_FAILURE;
 		}
@@ -22743,7 +22742,7 @@ BUILDIN_FUNC(adopt)
 		uint32 char_id = script_getnum(st, 2);
 
 		sd = map_charid2sd(char_id);
-		if (sd == NULL) {
+		if (sd == nullptr) {
 			ShowError("buildin_adopt: Non-existant parent character %d requested.\n", char_id);
 			return SCRIPT_CMD_FAILURE;
 		}
@@ -22753,7 +22752,7 @@ BUILDIN_FUNC(adopt)
 		const char *name = script_getstr(st, 3);
 
 		b_sd = map_nick2sd(name,false);
-		if (b_sd == NULL) {
+		if (b_sd == nullptr) {
 			ShowError("buildin_adopt: Non-existant baby character %s requested.\n", name);
 			return SCRIPT_CMD_FAILURE;
 		}
@@ -22761,13 +22760,13 @@ BUILDIN_FUNC(adopt)
 		uint32 char_id = script_getnum(st, 3);
 
 		b_sd = map_charid2sd(char_id);
-		if (b_sd == NULL) {
+		if (b_sd == nullptr) {
 			ShowError("buildin_adopt: Non-existant baby character %d requested.\n", char_id);
 			return SCRIPT_CMD_FAILURE;
 		}
 	}
 
-	response = pc_try_adopt(sd, map_charid2sd(sd->status.partner_id), b_sd);
+	e_adopt_responses response = pc_try_adopt(sd, map_charid2sd(sd->status.partner_id), b_sd);
 
 	if (response == ADOPT_ALLOWED) {
 		TBL_PC *p_sd = map_charid2sd(sd->status.partner_id);
@@ -22782,6 +22781,64 @@ BUILDIN_FUNC(adopt)
 	return SCRIPT_CMD_FAILURE;
 }
 
+/**
+ * unadopt("<parent_name>","<baby_name>"{,<independent_baby>});
+ * unadopt(<parent_id>,<baby_id>{,<independent_baby>});
+ */
+BUILDIN_FUNC(unadopt)
+{
+	TBL_PC *sd, *b_sd;
+
+	if (script_isstring(st, 2)) {
+		const char *name = script_getstr(st, 2);
+
+		sd = map_nick2sd(name,false);
+		if (sd == nullptr) {
+			ShowError("buildin_unadopt: Non-existant parent character %s requested.\n", name);
+			return SCRIPT_CMD_FAILURE;
+		}
+	} else {
+		uint32 char_id = script_getnum(st, 2);
+
+		sd = map_charid2sd(char_id);
+		if (sd == nullptr) {
+			ShowError("buildin_unadopt: Non-existant parent character %d requested.\n", char_id);
+			return SCRIPT_CMD_FAILURE;
+		}
+	}
+
+	if (script_isstring(st, 3)) {
+		const char *name = script_getstr(st, 3);
+
+		b_sd = map_nick2sd(name,false);
+		if (b_sd == nullptr) {
+			ShowError("buildin_unadopt: Non-existant baby character %s requested.\n", name);
+			return SCRIPT_CMD_FAILURE;
+		}
+	} else {
+		uint32 char_id = script_getnum(st, 3);
+
+		b_sd = map_charid2sd(char_id);
+		if (b_sd == nullptr) {
+			ShowError("buildin_unadopt: Non-existant baby character %d requested.\n", char_id);
+			return SCRIPT_CMD_FAILURE;
+		}
+	}
+
+	bool independent_baby = false;
+
+	if (script_hasdata(st, 4))
+		independent_baby = script_getnum(st, 4) != 0;
+
+	e_unadopt_responses response = pc_unadopt(sd, map_charid2sd(sd->status.partner_id), b_sd, independent_baby);
+
+	script_pushint(st, response);
+	if (response == UNADOPT_ALLOWED)
+		return SCRIPT_CMD_SUCCESS;
+	else
+		return SCRIPT_CMD_FAILURE;
+}
+
 /**
  * Returns the minimum or maximum of all the given parameters for integer variables.
  *
@@ -25217,6 +25274,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(navigateto,"s???????"),
 	BUILDIN_DEF(getguildalliance,"ii"),
 	BUILDIN_DEF(adopt,"vv"),
+	BUILDIN_DEF(unadopt, "vv?"),
 	BUILDIN_DEF(getexp2,"ii?"),
 	BUILDIN_DEF(recalculatestat,""),
 	BUILDIN_DEF(hateffect,"ii"),