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).
This commit is contained in:
Aleos 2020-03-06 09:16:18 -05:00
parent 496f362ec9
commit dc587df982
7 changed files with 245 additions and 25 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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