diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/char/int_pet.c | 15 | ||||
-rw-r--r-- | src/common/mmo.h | 1 | ||||
-rw-r--r-- | src/map/battle.c | 1 | ||||
-rw-r--r-- | src/map/battle.h | 1 | ||||
-rw-r--r-- | src/map/clif.c | 144 | ||||
-rw-r--r-- | src/map/clif.h | 15 | ||||
-rw-r--r-- | src/map/packets.h | 2 | ||||
-rw-r--r-- | src/map/packets_struct.h | 12 | ||||
-rw-r--r-- | src/map/pet.c | 163 | ||||
-rw-r--r-- | src/map/pet.h | 15 |
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 |