summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2018-06-29 11:33:11 +0200
committerGitHub <noreply@github.com>2018-06-29 11:33:11 +0200
commit9d24045d743a11eda0c825ea3c989fc5e78bc8af (patch)
tree91d8f55d2aed6fb58661fd7fada8f3f6e53ed814 /src
parentc419726752ebd1b532f487e5683f63232a6c237b (diff)
parent9876ae283e9ca68e60de3a0745a765e460d4c434 (diff)
downloadhercules-9d24045d743a11eda0c825ea3c989fc5e78bc8af.tar.gz
hercules-9d24045d743a11eda0c825ea3c989fc5e78bc8af.tar.bz2
hercules-9d24045d743a11eda0c825ea3c989fc5e78bc8af.tar.xz
hercules-9d24045d743a11eda0c825ea3c989fc5e78bc8af.zip
Merge pull request #2063 from dastgirp/2-petevol
Implemented Pet Evolution and Pet Feeding
Diffstat (limited to 'src')
-rw-r--r--src/char/int_pet.c15
-rw-r--r--src/common/mmo.h1
-rw-r--r--src/map/battle.c1
-rw-r--r--src/map/battle.h1
-rw-r--r--src/map/clif.c144
-rw-r--r--src/map/clif.h15
-rw-r--r--src/map/packets.h2
-rw-r--r--src/map/packets_struct.h12
-rw-r--r--src/map/pet.c163
-rw-r--r--src/map/pet.h15
10 files changed, 331 insertions, 38 deletions
diff --git a/src/char/int_pet.c b/src/char/int_pet.c
index 0ece11b51..f270f205d 100644
--- a/src/char/int_pet.c
+++ b/src/char/int_pet.c
@@ -66,19 +66,19 @@ int inter_pet_tosql(const struct s_pet *p)
if (p->pet_id == 0) {
// New pet.
if (SQL_ERROR == SQL->Query(inter->sql_handle, "INSERT INTO `%s` "
- "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`) "
- "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')",
+ "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`, `autofeed`) "
+ "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')",
pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id,
- p->equip, intimate, hungry, p->rename_flag, p->incubate)) {
+ p->equip, intimate, hungry, p->rename_flag, p->incubate, p->autofeed)) {
Sql_ShowDebug(inter->sql_handle);
return 0;
}
pet_id = (int)SQL->LastInsertId(inter->sql_handle);
} else {
// Update pet.
- if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incubate`='%d' WHERE `pet_id`='%d'",
+ if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incubate`='%d', `autofeed`='%d' WHERE `pet_id`='%d'",
pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id,
- p->equip, intimate, hungry, p->rename_flag, p->incubate, p->pet_id)) {
+ p->equip, intimate, hungry, p->rename_flag, p->incubate, p->autofeed, p->pet_id)) {
Sql_ShowDebug(inter->sql_handle);
return 0;
}
@@ -102,9 +102,9 @@ int inter_pet_fromsql(int pet_id, struct s_pet* p)
nullpo_ret(p);
memset(p, 0, sizeof(struct s_pet));
- //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`)
+ //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`, `autofeed`)
- if( SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate` FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) )
+ if( SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`,`autofeed` FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) )
{
Sql_ShowDebug(inter->sql_handle);
return 0;
@@ -124,6 +124,7 @@ int inter_pet_fromsql(int pet_id, struct s_pet* p)
SQL->GetData(inter->sql_handle, 9, &data, NULL); p->hungry = atoi(data);
SQL->GetData(inter->sql_handle, 10, &data, NULL); p->rename_flag = atoi(data);
SQL->GetData(inter->sql_handle, 11, &data, NULL); p->incubate = atoi(data);
+ SQL->GetData(inter->sql_handle, 12, &data, NULL); p->autofeed = atoi(data);
SQL->FreeResult(inter->sql_handle);
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 74d48dd47..0b4ba4a45 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -544,6 +544,7 @@ struct s_pet {
char name[NAME_LENGTH];
char rename_flag;
char incubate;
+ int autofeed;
};
struct s_homunculus { //[orn]
diff --git a/src/map/battle.c b/src/map/battle.c
index 6a961afeb..4d320704a 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -7319,6 +7319,7 @@ static const struct battle_data {
{ "features/rodex", &battle_config.feature_rodex, 1, 0, 1, },
{ "features/rodex_use_accountmail", &battle_config.feature_rodex_use_accountmail, 0, 0, 1, },
{ "features/enable_homun_autofeed", &battle_config.feature_enable_homun_autofeed, 1, 0, 1, },
+ { "features/enable_pet_autofeed", &battle_config.feature_enable_pet_autofeed, 1, 0, 1, },
{ "storage_use_item", &battle_config.storage_use_item, 0, 0, 1, },
{ "features/enable_attendance_system", &battle_config.feature_enable_attendance_system,1, 0, 1, },
{ "features/feature_attendance_endtime",&battle_config.feature_attendance_endtime, 1, 0, 99999999, },
diff --git a/src/map/battle.h b/src/map/battle.h
index c325daf0d..f4176f142 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -563,6 +563,7 @@ struct Battle_Config {
int feature_rodex_use_accountmail;
int feature_enable_homun_autofeed;
+ int feature_enable_pet_autofeed;
int storage_use_item;
diff --git a/src/map/clif.c b/src/map/clif.c
index aeaf03e43..c085c4fe4 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -9093,7 +9093,7 @@ void clif_feel_hate_reset(struct map_session_data *sd)
/// value:
/// 0 = disabled
/// 1 = enabled
-void clif_zc_config(struct map_session_data* sd, int type, int flag)
+void clif_zc_config(struct map_session_data* sd, enum CZ_CONFIG type, int flag)
{
int fd;
nullpo_retv(sd);
@@ -13755,6 +13755,115 @@ void clif_parse_ChangePetName(int fd, struct map_session_data *sd)
pet->change_name(sd, RFIFOP(fd,2));
}
+void clif_parse_pet_evolution(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+/// Request to Evolve the pet (CZ_PET_EVOLUTION) [Dastgir/Hercules]
+/// 09fb <Length>.W <EvolvedPetEggID>.W {<index>.W <amount>.W}*items
+void clif_parse_pet_evolution(int fd, struct map_session_data *sd)
+{
+ const struct PACKET_CZ_PET_EVOLUTION *p = RP2PTR(fd);
+ int i = 0, idx, petIndex;
+
+ Assert_retv(p->PacketLength >= (uint16)sizeof(struct PACKET_CZ_PET_EVOLUTION));
+
+ if (sd->status.pet_id == 0) {
+ clif->petEvolutionResult(fd, PET_EVOL_NO_CALLPET);
+ return;
+ }
+
+ ARR_FIND(0, MAX_INVENTORY, idx, sd->status.inventory[idx].card[0] == CARD0_PET &&
+ sd->status.pet_id == MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2]));
+
+ if (idx == MAX_INVENTORY) {
+ clif->petEvolutionResult(fd, PET_EVOL_NO_PETEGG);
+ return;
+ }
+
+ // Not Loyal Yet
+ if (sd->pd == NULL || sd->pd->pet.intimate < 900) {
+ clif->petEvolutionResult(fd, PET_EVOL_RG_FAMILIAR);
+ return;
+ }
+
+ ARR_FIND(0, MAX_PET_DB, petIndex, pet->db[petIndex].class_ == sd->pd->pet.class_);
+
+ if (petIndex == MAX_PET_DB) {
+ // Which error?
+ clif->petEvolutionResult(fd, PET_EVOL_UNKNOWN);
+ return;
+ }
+
+ // Client side validation is not done as it is insecure.
+ for (i = 0; i < VECTOR_LENGTH(pet->db[petIndex].evolve_data); i++) {
+ struct pet_evolve_data *ped = &VECTOR_INDEX(pet->db[petIndex].evolve_data, i);
+ if (ped->petEggId == p->EvolvedPetEggID) {
+ int j;
+ int pet_id;
+
+ if (VECTOR_LENGTH(ped->items) == 0) {
+ clif->petEvolutionResult(fd, PET_EVOL_NO_RECIPE);
+ return;
+ }
+ for (j = 0; j < VECTOR_LENGTH(ped->items); j++) {
+ struct itemlist_entry *list = &VECTOR_INDEX(ped->items, j);
+ int n = pc->search_inventory(sd, list->id);
+
+ if (n == INDEX_NOT_FOUND) {
+ clif->petEvolutionResult(fd, PET_EVOL_NO_MATERIAL);
+ return;
+ }
+ }
+
+ for (j = 0; j < VECTOR_LENGTH(ped->items); j++) {
+ struct itemlist_entry *list = &VECTOR_INDEX(ped->items, j);
+ int n = pc->search_inventory(sd, list->id);
+
+ if (pc->delitem(sd, n, list->amount, 0, DELITEM_NORMAL, LOG_TYPE_EGG) == 1) {
+ clif->petEvolutionResult(fd, PET_EVOL_NO_MATERIAL);
+ return;
+ }
+ }
+
+ // Return to Egg
+ pet->return_egg(sd, sd->pd);
+
+ if (pc->delitem(sd, idx, 1, 0, DELITEM_NORMAL, LOG_TYPE_EGG) == 1) {
+ clif->petEvolutionResult(fd, PET_EVOL_NO_PETEGG);
+ return;
+ }
+
+ pet_id = pet->search_petDB_index(ped->petEggId, PET_EGG);
+ if (pet_id >= 0) {
+ sd->catch_target_class = pet->db[pet_id].class_;
+
+ intif->create_pet(
+ sd->status.account_id, sd->status.char_id,
+ (short)pet->db[pet_id].class_, (short)mob->db(pet->db[pet_id].class_)->lv,
+ (short)pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate,
+ 100, 0, 1, pet->db[pet_id].jname);
+ clif->petEvolutionResult(fd, PET_EVOL_SUCCESS);
+ } else {
+ clif->petEvolutionResult(fd, PET_EVOL_UNKNOWN);
+ }
+ return;
+ }
+ }
+
+ clif->petEvolutionResult(fd, PET_EVOL_UNKNOWN);
+}
+
+/**
+ * Result of Pet Evolution (ZC_PET_EVOLUTION_RESULT)
+ * 0x9fc <Result>.L
+ */
+void clif_pet_evolution_result(int fd, enum pet_evolution_result result) {
+#if PACKETVER >= 20140122
+ WFIFOHEAD(fd, packet_len(0x9fc));
+ WFIFOW(fd, 0) = 0x9fc;
+ WFIFOL(fd, 2) = result;
+ WFIFOSET(fd, packet_len(0x9fc));
+#endif
+}
+
void clif_parse_GMKick(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
/// /kill (CZ_DISCONNECT_CHARACTER).
/// Request to disconnect a character.
@@ -16154,24 +16263,38 @@ void clif_parse_cz_config(int fd, struct map_session_data *sd) __attribute__((no
/// 02d8 <type>.L <value>.L
/// type:
/// 0 = open equip window
+/// 2 = pet autofeeding
/// 3 = homunculus autofeeding
/// value:
/// 0 = disabled
/// 1 = enabled
void clif_parse_cz_config(int fd, struct map_session_data *sd)
{
- int type = RFIFOL(fd, 2);
+ enum CZ_CONFIG type = RFIFOL(fd, 2);
int flag = RFIFOL(fd, 6);
- if (type == CZ_CONFIG_OPEN_EQUIPMENT_WINDOW) {
+ switch (type) {
+ case CZ_CONFIG_OPEN_EQUIPMENT_WINDOW:
sd->status.show_equip = flag;
- } else if (type == CZ_CONFIG_HOMUNCULUS_AUTOFEEDING) {
- struct homun_data *hd;
- hd = sd->hd;
+ break;
+ case CZ_CONFIG_PET_AUTOFEEDING: {
+ struct pet_data *pd = sd->pd;
+ nullpo_retv(pd);
+ if (pd->petDB->autofeed == 0) {
+ clif->message(fd, "Autofeed is disabled for this pet.");
+ return;
+ }
+ pd->pet.autofeed = flag;
+ break;
+ }
+ case CZ_CONFIG_HOMUNCULUS_AUTOFEEDING: {
+ struct homun_data *hd = sd->hd;
nullpo_retv(hd);
hd->homunculus.autofeed = flag;
- } else {
- ShowWarning("clif_parse_cz_config: Unsupported type has been received (%d).", type);
+ break;
+ }
+ default:
+ ShowWarning("clif_parse_cz_config: Unsupported type has been received (%u).\n", type);
return;
}
clif->zc_config(sd, type, flag);
@@ -21991,4 +22114,9 @@ void clif_defaults(void) {
clif->pReqStyleChange = clif_parse_cz_req_style_change;
clif->cz_req_style_change_sub = clif_cz_req_style_change_sub;
clif->style_change_response = clif_style_change_response;
+
+ // -- Pet Evolution
+ clif->pPetEvolution = clif_parse_pet_evolution;
+ clif->petEvolutionResult = clif_pet_evolution_result;
+
}
diff --git a/src/map/clif.h b/src/map/clif.h
index 4b625023f..eb9881533 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -592,6 +592,17 @@ enum private_airship {
P_AIRSHIP_ITEM_INVALID
};
+/** Pet Evolution Results */
+enum pet_evolution_result {
+ PET_EVOL_UNKNOWN = 0x0,
+ PET_EVOL_NO_CALLPET = 0x1,
+ PET_EVOL_NO_PETEGG = 0x2,
+ PET_EVOL_NO_RECIPE = 0x3,
+ PET_EVOL_NO_MATERIAL = 0x4,
+ PET_EVOL_RG_FAMILIAR = 0x5,
+ PET_EVOL_SUCCESS = 0x6,
+};
+
/**
* Structures
**/
@@ -834,7 +845,7 @@ struct clif_interface {
void (*mission_info) (struct map_session_data *sd, int mob_id, unsigned char progress);
void (*feel_hate_reset) (struct map_session_data *sd);
void (*partytickack) (struct map_session_data* sd, bool flag);
- void (*zc_config) (struct map_session_data *sd, int type, int flag);
+ void (*zc_config) (struct map_session_data *sd, enum CZ_CONFIG type, int flag);
void (*viewequip_ack) (struct map_session_data* sd, struct map_session_data* tsd);
void (*equpcheckbox) (struct map_session_data* sd);
void (*displayexp) (struct map_session_data *sd, uint64 exp, char type, bool is_quest);
@@ -1484,6 +1495,8 @@ struct clif_interface {
void (*pReqStyleChange) (int fd, struct map_session_data *sd);
void (*cz_req_style_change_sub) (struct map_session_data *sd, int type, int16 idx, bool isitem);
void (*style_change_response) (struct map_session_data *sd, enum stylist_shop flag);
+ void (*pPetEvolution) (int fd, struct map_session_data *sd);
+ void (*petEvolutionResult) (int fd, enum pet_evolution_result result);
};
#ifdef HERCULES_CORE
diff --git a/src/map/packets.h b/src/map/packets.h
index e5fda598d..ebd971005 100644
--- a/src/map/packets.h
+++ b/src/map/packets.h
@@ -3029,7 +3029,7 @@ packet(0x96e,-1,clif->ackmergeitems);
// 2014-01-22aRagexeRE
#if PACKETVER >= 20140122
// new packets
- packet(0x09fb,-1,clif->pDull/*,XXX*/); // CZ_PET_EVOLUTION
+ packet(0x09fb,-1,clif->pPetEvolution); // CZ_PET_EVOLUTION
packet(0x09fc,6); // ZC_PET_EVOLUTION_RESULT
packet(0x09fd,-1); // ZC_NOTIFY_MOVEENTRY11
packet(0x09fe,-1); // ZC_NOTIFY_NEWENTRY11
diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h
index d152ffd2a..bcdf1061a 100644
--- a/src/map/packets_struct.h
+++ b/src/map/packets_struct.h
@@ -1762,6 +1762,18 @@ struct PACKET_ZC_STYLE_CHANGE_RES {
int8 flag;
} __attribute__((packed));
+struct pet_evolution_items {
+ int16 index;
+ int16 amount;
+} __attribute__((packed));
+
+struct PACKET_CZ_PET_EVOLUTION {
+ int16 PacketType;
+ uint16 PacketLength;
+ int16 EvolvedPetEggID;
+ // struct pet_evolution_items items[];
+} __attribute__((packed));
+
#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
#pragma pack(pop)
#endif // not NetBSD < 6 / Solaris
diff --git a/src/map/pet.c b/src/map/pet.c
index 4bac79dc8..58c26d1ce 100644
--- a/src/map/pet.c
+++ b/src/map/pet.c
@@ -85,8 +85,21 @@ void pet_set_intimate(struct pet_data *pd, int value)
sd = pd->msd;
pd->pet.intimate = value;
+
if( (intimate >= battle_config.pet_equip_min_friendly && pd->pet.intimate < battle_config.pet_equip_min_friendly) || (intimate < battle_config.pet_equip_min_friendly && pd->pet.intimate >= battle_config.pet_equip_min_friendly) )
status_calc_pc(sd,SCO_NONE);
+
+ /* Pet is lost, delete the egg */
+ if (value <= 0) {
+ int i;
+
+ ARR_FIND(0, MAX_INVENTORY, i, sd->status.inventory[i].card[0] == CARD0_PET &&
+ pd->pet.pet_id == MakeDWord(sd->status.inventory[i].card[1], sd->status.inventory[i].card[2]));
+
+ if (i != MAX_INVENTORY) {
+ pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_EGG);
+ }
+ }
}
int pet_create_egg(struct map_session_data *sd, int item_id)
@@ -233,6 +246,13 @@ int pet_hungry(int tid, int64 tick, int id, intptr_t data) {
return 1; //You lost the pet already, the rest is irrelevant.
pd->pet.hungry--;
+ /* Pet Autofeed */
+ if (battle_config.feature_enable_homun_autofeed != 0) {
+ if (pd->petDB->autofeed == 1 && pd->pet.autofeed == 1 && pd->pet.hungry <= 25) {
+ pet->food(sd, pd);
+ }
+ }
+
if( pd->pet.hungry < 0 )
{
pet_stop_attack(pd);
@@ -311,23 +331,21 @@ int pet_performance(struct map_session_data *sd, struct pet_data *pd)
int pet_return_egg(struct map_session_data *sd, struct pet_data *pd)
{
- struct item tmp_item;
- int flag;
+ int i;
nullpo_retr(1, sd);
nullpo_retr(1, pd);
pet->lootitem_drop(pd,sd);
- memset(&tmp_item,0,sizeof(tmp_item));
- tmp_item.nameid = pd->petDB->EggID;
- tmp_item.identify = 1;
- tmp_item.card[0] = CARD0_PET;
- tmp_item.card[1] = GetWord(pd->pet.pet_id,0);
- tmp_item.card[2] = GetWord(pd->pet.pet_id,1);
- tmp_item.card[3] = pd->pet.rename_flag;
- if((flag = pc->additem(sd,&tmp_item,1,LOG_TYPE_EGG))) {
- clif->additem(sd,0,0,flag);
- map->addflooritem(&sd->bl, &tmp_item, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false);
+
+ // Pet Evolution
+ ARR_FIND(0, MAX_INVENTORY, i, sd->status.inventory[i].card[0] == CARD0_PET &&
+ pd->pet.pet_id == MakeDWord(sd->status.inventory[i].card[1], sd->status.inventory[i].card[2]));
+
+ if (i != MAX_INVENTORY) {
+ sd->status.inventory[i].identify = 1;
+ sd->status.inventory[i].bound = IBT_NONE;
}
+
pd->pet.incubate = 1;
unit->free(&pd->bl,CLR_OUTSIGHT);
@@ -462,19 +480,23 @@ int pet_recv_petdata(int account_id,struct s_pet *p,int flag) {
}
if(p->incubate == 1) {
int i;
- //Delete egg from inventory. [Skotlex]
- for (i = 0; i < MAX_INVENTORY; i++) {
- if(sd->status.inventory[i].card[0] == CARD0_PET &&
- p->pet_id == MakeDWord(sd->status.inventory[i].card[1], sd->status.inventory[i].card[2]))
- break;
- }
- if(i >= MAX_INVENTORY) {
+ // Get Egg Index
+ ARR_FIND(0, MAX_INVENTORY, i, sd->status.inventory[i].card[0] == CARD0_PET &&
+ p->pet_id == MakeDWord(sd->status.inventory[i].card[1], sd->status.inventory[i].card[2]));
+
+ if(i == MAX_INVENTORY) {
ShowError("pet_recv_petdata: Hatching pet (%d:%s) aborted, couldn't find egg in inventory for removal!\n",p->pet_id, p->name);
sd->status.pet_id = 0;
return 1;
}
- if (!pet->birth_process(sd,p)) //Pet hatched. Delete egg.
- pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_EGG);
+
+
+ if (!pet->birth_process(sd,p)) {
+ // Pet Evolution, Hide the egg by setting identify to 0 [Dastgir/Hercules]
+ sd->status.inventory[i].identify = 0;
+ // bind the egg to the character to avoid moving it via forged packets [Asheraf]
+ sd->status.inventory[i].bound = IBT_CHARACTER;
+ }
} else {
pet->data_init(sd,p);
if(sd->pd && sd->bl.prev != NULL) {
@@ -1359,6 +1381,14 @@ int pet_read_db_sub(struct config_setting_t *it, int n, const char *source)
if (libconfig->setting_lookup_int(it, "ChangeTargetRate", &i32))
pet->db[n].change_target_rate = i32;
+ // Pet Evolution
+ if ((t = libconfig->setting_get_member(it, "Evolve")) && config_setting_is_group(t)) {
+ pet->read_db_sub_evolution(t, n);
+ }
+
+ if ((t = libconfig->setting_get_member(it, "AutoFeed")) && (i32 = libconfig->setting_get_bool(t)))
+ pet->db[n].autofeed = i32;
+
if (libconfig->setting_lookup_string(it, "PetScript", &str))
pet->db[n].pet_script = *str ? script->parse(str, source, -pet->db[n].class_, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
@@ -1368,6 +1398,81 @@ int pet_read_db_sub(struct config_setting_t *it, int n, const char *source)
return pet->db[n].class_;
}
+/**
+ * Read Pet Evolution Database [Dastgir/Hercules]
+ * @param t libconfig setting
+ * @param n Pet DB Index
+ */
+void pet_read_db_sub_evolution(struct config_setting_t *t, int n)
+{
+ struct config_setting_t *pett;
+ int i = 0;
+ const char *str = NULL;
+
+ nullpo_retv(t);
+ Assert_retv(n >= 0 && n < MAX_PET_DB);
+
+ VECTOR_INIT(pet->db[n].evolve_data);
+
+ while ((pett = libconfig->setting_get_elem(t, i))) {
+ if (config_setting_is_group(pett)) {
+ struct pet_evolve_data ped;
+ struct item_data *data;
+ struct config_setting_t *item;
+ int j = 0, i32 = 0;
+
+ str = config_setting_name(pett);
+
+ if (!(data = itemdb->name2id(str))) {
+ ShowWarning("pet_read_evolve_db_sub: Invalid Egg '%s' in Pet #%d, skipping.\n", str, pet->db[n].class_);
+ return;
+ } else {
+ ped.petEggId = data->nameid;
+ }
+
+ VECTOR_INIT(ped.items);
+
+ while ((item = libconfig->setting_get_elem(pett, j))) {
+ struct itemlist_entry list = { 0 };
+ int quantity = 0;
+
+ str = config_setting_name(item);
+ data = itemdb->search_name(str);
+
+ if (!data) {
+ ShowWarning("pet_read_evolve_db_sub: required item %s not found in egg %d\n", str, ped.petEggId);
+ j++;
+ continue;
+ }
+
+ list.id = data->nameid;
+
+ if (mob->get_const(item, &i32) && i32 >= 0) {
+ quantity = i32;
+ }
+
+ if (quantity <= 0) {
+ ShowWarning("pet_read_evolve_db_sub: invalid quantity %d for egg %d\n", quantity, ped.petEggId);
+ j++;
+ continue;
+ }
+
+ list.amount = quantity;
+
+ VECTOR_ENSURE(ped.items, 1, 1);
+ VECTOR_PUSH(ped.items, list);
+
+ j++;
+
+ }
+
+ VECTOR_ENSURE(pet->db[n].evolve_data, 1, 1);
+ VECTOR_PUSH(pet->db[n].evolve_data, ped);
+ }
+ i++;
+ }
+}
+
bool pet_read_db_sub_intimacy(int idx, struct config_setting_t *t)
{
int i32 = 0;
@@ -1396,6 +1501,7 @@ void pet_read_db_clear(void)
// Remove any previous scripts in case reloaddb was invoked.
for (i = 0; i < MAX_PET_DB; i++) {
+ int j;
if (pet->db[i].pet_script) {
script->free_code(pet->db[i].pet_script);
pet->db[i].pet_script = NULL;
@@ -1404,6 +1510,11 @@ void pet_read_db_clear(void)
script->free_code(pet->db[i].equip_script);
pet->db[i].equip_script = NULL;
}
+
+ for (j = 0; j < VECTOR_LENGTH(pet->db[i].evolve_data); j++) {
+ VECTOR_CLEAR(VECTOR_INDEX(pet->db[i].evolve_data, j).items);
+ }
+ VECTOR_CLEAR(pet->db[i].evolve_data);
}
memset(pet->db, 0, sizeof(pet->db));
return;
@@ -1437,6 +1548,7 @@ int do_final_pet(void)
int i;
for( i = 0; i < MAX_PET_DB; i++ )
{
+ int j;
if( pet->db[i].pet_script )
{
script->free_code(pet->db[i].pet_script);
@@ -1447,9 +1559,16 @@ int do_final_pet(void)
script->free_code(pet->db[i].equip_script);
pet->db[i].equip_script = NULL;
}
+
+ /* Pet Evolution [Dastgir/Hercules] */
+ for (j = 0; j < VECTOR_LENGTH(pet->db[i].evolve_data); j++) {
+ VECTOR_CLEAR(VECTOR_INDEX(pet->db[i].evolve_data, j).items);
+ }
+ VECTOR_CLEAR(pet->db[i].evolve_data);
}
ers_destroy(pet->item_drop_ers);
ers_destroy(pet->item_drop_list_ers);
+
return 0;
}
void pet_defaults(void) {
@@ -1503,4 +1622,6 @@ void pet_defaults(void) {
pet->read_db_sub = pet_read_db_sub;
pet->read_db_sub_intimacy = pet_read_db_sub_intimacy;
pet->read_db_clear = pet_read_db_clear;
+
+ pet->read_db_sub_evolution = pet_read_db_sub_evolution;
}
diff --git a/src/map/pet.h b/src/map/pet.h
index d341be97c..b3a16c5d7 100644
--- a/src/map/pet.h
+++ b/src/map/pet.h
@@ -30,6 +30,12 @@
#define MAX_PET_DB 300
#define MAX_PETLOOT_SIZE 30
+/** Pet Evolution [Dastgir/Hercules] */
+struct pet_evolve_data {
+ int petEggId;
+ VECTOR_DECL(struct itemlist_entry) items;
+};
+
struct s_pet_db {
short class_;
char name[NAME_LENGTH],jname[NAME_LENGTH];
@@ -50,8 +56,12 @@ struct s_pet_db {
int attack_rate;
int defence_attack_rate;
int change_target_rate;
+ int autofeed;
struct script_code *equip_script;
struct script_code *pet_script;
+
+ /* Pet Evolution */
+ VECTOR_DECL(struct pet_evolve_data) evolve_data;
};
enum { PET_CLASS,PET_CATCH,PET_EGG,PET_EQUIP,PET_FOOD };
@@ -127,6 +137,7 @@ struct pet_interface {
struct s_pet_db db[MAX_PET_DB];
struct eri *item_drop_ers; //For loot drops delay structures.
struct eri *item_drop_list_ers;
+
/* */
int (*init) (bool minimal);
int (*final) (void);
@@ -172,6 +183,10 @@ struct pet_interface {
int (*read_db_sub) (struct config_setting_t *it, int n, const char *source);
bool (*read_db_sub_intimacy) (int idx, struct config_setting_t *t);
void (*read_db_clear) (void);
+
+ /* Pet Evolution [Dastgir/Hercules] */
+ void (*read_db_sub_evolution) (struct config_setting_t *t, int n);
+
};
#ifdef HERCULES_CORE