summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/map/clif.c114
-rw-r--r--src/map/clif.h13
-rw-r--r--src/map/packets.h2
-rw-r--r--src/map/packets_struct.h12
-rw-r--r--src/map/pet.c153
-rw-r--r--src/map/pet.h14
6 files changed, 286 insertions, 22 deletions
diff --git a/src/map/clif.c b/src/map/clif.c
index 86b159288..c085c4fe4 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -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.
@@ -22005,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 a8a9ddf70..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
**/
@@ -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 4e3503b05..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)
@@ -318,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);
@@ -469,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) {
@@ -1366,6 +1381,11 @@ 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;
@@ -1378,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;
@@ -1406,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;
@@ -1414,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;
@@ -1447,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);
@@ -1457,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) {
@@ -1513,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 434b07015..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];
@@ -53,6 +59,9 @@ struct s_pet_db {
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 };
@@ -128,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);
@@ -173,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