diff options
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/atcommand.c | 2 | ||||
-rw-r--r-- | src/map/clif.c | 281 | ||||
-rw-r--r-- | src/map/clif.h | 1 | ||||
-rw-r--r-- | src/map/date.c | 7 | ||||
-rw-r--r-- | src/map/date.h | 1 | ||||
-rw-r--r-- | src/map/guild.c | 26 | ||||
-rw-r--r-- | src/map/guild.h | 2 | ||||
-rw-r--r-- | src/map/npc.c | 11 | ||||
-rw-r--r-- | src/map/packets_struct.h | 8 | ||||
-rw-r--r-- | src/map/pc.c | 52 | ||||
-rw-r--r-- | src/map/pc.h | 2 | ||||
-rw-r--r-- | src/map/quest.c | 21 | ||||
-rw-r--r-- | src/map/quest.h | 2 | ||||
-rw-r--r-- | src/map/script.c | 387 | ||||
-rw-r--r-- | src/map/script.h | 3 |
15 files changed, 592 insertions, 214 deletions
diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 19a7e360b..872c31330 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -5605,7 +5605,7 @@ ACMD(changegm) { return false; } - guild->gm_change(sd->status.guild_id, pl_sd); + guild->gm_change(sd->status.guild_id, pl_sd->status.char_id); return true; } diff --git a/src/map/clif.c b/src/map/clif.c index 524378439..905b6a3ce 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -2442,7 +2442,9 @@ void clif_addcards2(unsigned short *cards, struct item* item) { /// 02d4 <index>.W <amount>.W <name id>.W <identified>.B <damaged>.B <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W <equip location>.W <item type>.B <result>.B <expire time>.L <bindOnEquipType>.W (ZC_ITEM_PICKUP_ACK3) /// 0990 <index>.W <amount>.W <name id>.W <identified>.B <damaged>.B <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W <equip location>.L <item type>.B <result>.B <expire time>.L <bindOnEquipType>.W (ZC_ITEM_PICKUP_ACK_V5) /// 0a0c <index>.W <amount>.W <name id>.W <identified>.B <damaged>.B <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W <equip location>.L <item type>.B <result>.B <expire time>.L <bindOnEquipType>.W (ZC_ITEM_PICKUP_ACK_V6) -void clif_additem(struct map_session_data *sd, int n, int amount, int fail) { +/// 0a37 <index>.W <amount>.W <name id>.W <identified>.B <damaged>.B <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W <equip location>.L <item type>.B <result>.B <expire time>.L <bindOnEquipType>.W <favorite>.B <view id>.W (ZC_ITEM_PICKUP_ACK_V7) +void clif_additem(struct map_session_data *sd, int n, int amount, int fail) +{ struct packet_additem p; nullpo_retv(sd); @@ -2483,6 +2485,10 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) { #if PACKETVER >= 20150226 clif->add_item_options(&p.option_data[0], &sd->status.inventory[n]); #endif +#if PACKETVER >= 20160921 + p.favorite = sd->status.inventory[n].favorite; + p.look = sd->inventory_data[n]->look; +#endif } p.result = (unsigned char)fail; @@ -2978,13 +2984,6 @@ void clif_updatestatus(struct map_session_data *sd,int type) break; case SP_HP: WFIFOL(fd,4)=sd->battle_status.hp; - // TODO: Won't these overwrite the current packet? - if( map->list[sd->bl.m].hpmeter_visible ) - clif->hpmeter(sd); - if( !battle_config.party_hp_mode && sd->status.party_id ) - clif->party_hp(sd); - if( sd->bg_id ) - clif->bg_hp(sd); break; case SP_SP: WFIFOL(fd,4)=sd->battle_status.sp; @@ -3134,6 +3133,21 @@ void clif_updatestatus(struct map_session_data *sd,int type) return; } WFIFOSET(fd,len); + + // Additional update packets that should be sent right after + switch (type) { + case SP_BASELEVEL: + pc->update_job_and_level(sd); + break; + case SP_HP: + if (map->list[sd->bl.m].hpmeter_visible) + clif->hpmeter(sd); + if (!battle_config.party_hp_mode && sd->status.party_id) + clif->party_hp(sd); + if (sd->bg_id) + clif->bg_hp(sd); + break; + } } /// Notifies client of a parameter change of an another player (ZC_PAR_CHANGE_USER). @@ -6345,10 +6359,13 @@ void clif_vendinglist(struct map_session_data* sd, unsigned int id, struct s_ven const int offset = 12; #endif -#if PACKETVER >= 20150226 +#if PACKETVER < 20150226 + const int item_length = 22; +// [4144] date 20160921 not confirmend. Can be bigger or smaller +#elif PACKETVER < 20160921 const int item_length = 47; #else - const int item_length = 22; + const int item_length = 53; #endif nullpo_retv(sd); @@ -6381,6 +6398,11 @@ void clif_vendinglist(struct map_session_data* sd, unsigned int id, struct s_ven #if PACKETVER >= 20150226 clif->add_item_options(WFIFOP(fd, offset + 22 + i * item_length), &vsd->status.cart[index]); #endif +// [4144] date 20160921 not confirmend. Can be bigger or smaller +#if PACKETVER >= 20160921 + WFIFOL(fd, offset + 47 + i * item_length) = pc->item_equippoint(sd, data); + WFIFOW(fd, offset + 51 + i * item_length) = data->look; +#endif } WFIFOSET(fd,WFIFOW(fd,2)); } @@ -6511,6 +6533,7 @@ void clif_party_created(struct map_session_data *sd,int result) /// Adds new member to a party. /// 0104 <account id>.L <role>.L <x>.W <y>.W <state>.B <party name>.24B <char name>.24B <map name>.16B (ZC_ADD_MEMBER_TO_GROUP) /// 01e9 <account id>.L <role>.L <x>.W <y>.W <state>.B <party name>.24B <char name>.24B <map name>.16B <item pickup rule>.B <item share rule>.B (ZC_ADD_MEMBER_TO_GROUP2) +/// 0a43 <account id>.L <role>.L <class>.W <base level>.W <x>.W <y>.W <state>.B <party name>.24B <char name>.24B <map name>.16B <item pickup rule>.B <item share rule>.B (ZC_ADD_MEMBER_TO_GROUP3) /// role: /// 0 = leader /// 1 = normal @@ -6519,35 +6542,50 @@ void clif_party_created(struct map_session_data *sd,int result) /// 1 = disconnected void clif_party_member_info(struct party_data *p, struct map_session_data *sd) { - unsigned char buf[81]; int i; +#if PACKETVER < 20170502 + unsigned char buf[81]; + const int cmd = 0x1e9; + const int offset = 0; +#else + unsigned char buf[85]; +// [4144] probably 0xa43 packet can works on older clients because in client was added in 2015-10-07 + const int cmd = 0xa43; + int offset = 4; +#endif nullpo_retv(p); nullpo_retv(sd); if (!sd) { //Pick any party member (this call is used when changing item share rules) - ARR_FIND( 0, MAX_PARTY, i, p->data[i].sd != 0 ); + ARR_FIND(0, MAX_PARTY, i, p->data[i].sd != 0); } else { - ARR_FIND( 0, MAX_PARTY, i, p->data[i].sd == sd ); + ARR_FIND(0, MAX_PARTY, i, p->data[i].sd == sd); } - if (i >= MAX_PARTY) return; //Should never happen... + if (i >= MAX_PARTY) + return; //Should never happen... sd = p->data[i].sd; - WBUFW(buf, 0) = 0x1e9; + WBUFW(buf, 0) = cmd; WBUFL(buf, 2) = sd->status.account_id; - WBUFL(buf, 6) = (p->party.member[i].leader)?0:1; - WBUFW(buf,10) = sd->bl.x; - WBUFW(buf,12) = sd->bl.y; - WBUFB(buf,14) = (p->party.member[i].online)?0:1; - memcpy(WBUFP(buf,15), p->party.name, NAME_LENGTH); - memcpy(WBUFP(buf,39), sd->status.name, NAME_LENGTH); - mapindex->getmapname_ext(map->list[sd->bl.m].custom_name ? map->list[map->list[sd->bl.m].instance_src_map].name : map->list[sd->bl.m].name, WBUFP(buf,63)); - WBUFB(buf,79) = (p->party.item&1)?1:0; - WBUFB(buf,80) = (p->party.item&2)?1:0; - clif->send(buf,packet_len(0x1e9),&sd->bl,PARTY); + WBUFL(buf, 6) = (p->party.member[i].leader) ? 0 : 1; +#if PACKETVER >= 20170502 + WBUFW(buf, 10) = sd->status.class; + WBUFW(buf, 12) = sd->status.base_level; +#endif + WBUFW(buf, offset + 10) = sd->bl.x; + WBUFW(buf, offset + 12) = sd->bl.y; + WBUFB(buf, offset + 14) = (p->party.member[i].online) ? 0 : 1; + memcpy(WBUFP(buf, offset + 15), p->party.name, NAME_LENGTH); + memcpy(WBUFP(buf, offset + 39), sd->status.name, NAME_LENGTH); + mapindex->getmapname_ext(map->list[sd->bl.m].custom_name ? map->list[map->list[sd->bl.m].instance_src_map].name : map->list[sd->bl.m].name, WBUFP(buf, offset + 63)); + WBUFB(buf, offset + 79) = (p->party.item & 1) ? 1 : 0; + WBUFB(buf, offset + 80) = (p->party.item & 2) ? 1 : 0; + clif->send(buf, packet_len(cmd), &sd->bl, PARTY); } /// Sends party information (ZC_GROUP_LIST). /// 00fb <packet len>.W <party name>.24B { <account id>.L <nick>.24B <map name>.16B <role>.B <state>.B }* +/// 0a44 <packet len>.W <party name>.24B { <account id>.L <nick>.24B <map name>.16B <role>.B <state>.B <class>.W <base level>.W }* <item pickup rule>.B <item share rule>.B <unknown>.L /// role: /// 0 = leader /// 1 = normal @@ -6556,37 +6594,78 @@ void clif_party_member_info(struct party_data *p, struct map_session_data *sd) /// 1 = disconnected void clif_party_info(struct party_data* p, struct map_session_data *sd) { - unsigned char buf[2+2+NAME_LENGTH+(4+NAME_LENGTH+MAP_NAME_LENGTH_EXT+1+1)*MAX_PARTY]; struct map_session_data* party_sd = NULL; int i, c; +#if PACKETVER < 20170502 + const int cmd = 0xfb; + const int size = 46; + unsigned char buf[2 + 2 + NAME_LENGTH + 46 * MAX_PARTY]; +#else +// [4144] probably 0xa44 packet can works on older clients because in client was added in 2015-10-07 + const int cmd = 0xa44; + const int size = 50; + unsigned char buf[2 + 2 + NAME_LENGTH + 50 * MAX_PARTY + 6]; +#endif nullpo_retv(p); - WBUFW(buf,0) = 0xfb; - memcpy(WBUFP(buf,4), p->party.name, NAME_LENGTH); + WBUFW(buf, 0) = cmd; + memcpy(WBUFP(buf, 4), p->party.name, NAME_LENGTH); for(i = 0, c = 0; i < MAX_PARTY; i++) { - struct party_member* m = &p->party.member[i]; - if(!m->account_id) continue; + struct party_member *m = &p->party.member[i]; + if (!m->account_id) + continue; - if(party_sd == NULL) party_sd = p->data[i].sd; + if (party_sd == NULL) + party_sd = p->data[i].sd; - WBUFL(buf,28+c*46) = m->account_id; - memcpy(WBUFP(buf,28+c*46+4), m->name, NAME_LENGTH); - mapindex->getmapname_ext(mapindex_id2name(m->map), WBUFP(buf,28+c*46+28)); - WBUFB(buf,28+c*46+44) = (m->leader) ? 0 : 1; - WBUFB(buf,28+c*46+45) = (m->online) ? 0 : 1; + WBUFL(buf, 28 + c * size) = m->account_id; + memcpy(WBUFP(buf, 28 + c * size + 4), m->name, NAME_LENGTH); + mapindex->getmapname_ext(mapindex_id2name(m->map), WBUFP(buf, 28 + c * size + 28)); + WBUFB(buf, 28 + c * size + 44) = (m->leader) ? 0 : 1; + WBUFB(buf, 28 + c * size + 45) = (m->online) ? 0 : 1; +#if PACKETVER >= 20170502 + WBUFW(buf, 28 + c * size + 46) = m->class; + WBUFW(buf, 28 + c * size + 48) = m->lv; +#endif c++; } - WBUFW(buf,2) = 28+c*46; +#if PACKETVER < 20170502 + WBUFW(buf, 2) = 28 + c * size; +#else + WBUFB(buf, 28 + c * size) = (p->party.item & 1) ? 1 : 0; + WBUFB(buf, 28 + c * size + 1) = (p->party.item & 2) ? 1 : 0; + WBUFL(buf, 28 + c * size + 2) = 0; // unknown + WBUFW(buf, 2) = 28 + c * size + 6; +#endif - if(sd) { // send only to self - clif->send(buf, WBUFW(buf,2), &sd->bl, SELF); + if (sd) { // send only to self + clif->send(buf, WBUFW(buf, 2), &sd->bl, SELF); } else if (party_sd) { // send to whole party - clif->send(buf, WBUFW(buf,2), &party_sd->bl, PARTY); + clif->send(buf, WBUFW(buf, 2), &party_sd->bl, PARTY); } } +/// Updates the job and level of a party member +/// 0abd <account id>.L <job>.W <level>.W +void clif_party_job_and_level(struct map_session_data *sd) +{ +// [4144] packet 0xabd added in client in 2017-02-15 because this probably it can works for clients older than 20170502 +#if PACKETVER >= 20170502 + unsigned char buf[10]; + + nullpo_retv(sd); + + WBUFW(buf, 0) = 0xabd; + WBUFL(buf, 2) = sd->status.account_id; + WBUFW(buf, 6) = sd->status.class; + WBUFW(buf, 8) = sd->status.base_level; + + clif_send(buf, packet_len(0xabd), &sd->bl, PARTY); +#endif +} + /// The player's 'party invite' state, sent during login (ZC_PARTY_CONFIG). /// 02c9 <flag>.B /// flag: @@ -7433,36 +7512,48 @@ void clif_guild_masterormember(struct map_session_data *sd) /// Guild basic information (Territories [Valaris]) /// 0150 <guild id>.L <level>.L <member num>.L <member max>.L <exp>.L <max exp>.L <points>.L <honor>.L <virtue>.L <emblem id>.L <name>.24B <master name>.24B <manage land>.16B (ZC_GUILD_INFO) /// 01b6 <guild id>.L <level>.L <member num>.L <member max>.L <exp>.L <max exp>.L <points>.L <honor>.L <virtue>.L <emblem id>.L <name>.24B <master name>.24B <manage land>.16B <zeny>.L (ZC_GUILD_INFO2) -void clif_guild_basicinfo(struct map_session_data *sd) { +void clif_guild_basicinfo(struct map_session_data *sd) +{ int fd; struct guild *g; +#if PACKETVER < 20160622 + const int cmd = 0x1b6; //0x150; [4144] this is packet for older versions? +#else + const int cmd = 0xa84; +#endif + nullpo_retv(sd); fd = sd->fd; - if( (g = sd->guild) == NULL ) + if ((g = sd->guild) == NULL) return; - WFIFOHEAD(fd,packet_len(0x1b6)); - WFIFOW(fd, 0)=0x1b6;//0x150; - WFIFOL(fd, 2)=g->guild_id; - WFIFOL(fd, 6)=g->guild_lv; - WFIFOL(fd,10)=g->connect_member; - WFIFOL(fd,14)=g->max_member; - WFIFOL(fd,18)=g->average_lv; - WFIFOL(fd,22)=(uint32)cap_value(g->exp,0,INT32_MAX); - WFIFOL(fd,26)=g->next_exp; - WFIFOL(fd,30)=0; // Tax Points - WFIFOL(fd,34)=0; // Honor: (left) Vulgar [-100,100] Famed (right) - WFIFOL(fd,38)=0; // Virtue: (down) Wicked [-100,100] Righteous (up) - WFIFOL(fd,42)=g->emblem_id; - memcpy(WFIFOP(fd,46),g->name, NAME_LENGTH); - memcpy(WFIFOP(fd,70),g->master, NAME_LENGTH); - - safestrncpy(WFIFOP(fd,94),msg_sd(sd,300+guild->checkcastles(g)),16); // "'N' castles" - WFIFOL(fd,110) = 0; // zeny + WFIFOHEAD(fd, packet_len(cmd)); + WFIFOW(fd, 0) = cmd; + WFIFOL(fd, 2) = g->guild_id; + WFIFOL(fd, 6) = g->guild_lv; + WFIFOL(fd, 10) = g->connect_member; + WFIFOL(fd, 14) = g->max_member; + WFIFOL(fd, 18) = g->average_lv; + WFIFOL(fd, 22) = (uint32)cap_value(g->exp, 0, INT32_MAX); + WFIFOL(fd, 26) = g->next_exp; + WFIFOL(fd, 30) = 0; // Tax Points + WFIFOL(fd, 34) = 0; // Honor: (left) Vulgar [-100,100] Famed (right) + WFIFOL(fd, 38) = 0; // Virtue: (down) Wicked [-100,100] Righteous (up) + WFIFOL(fd, 42) = g->emblem_id; + memcpy(WFIFOP(fd, 46), g->name, NAME_LENGTH); +#if PACKETVER < 20160622 + memcpy(WFIFOP(fd, 70), g->master, NAME_LENGTH); + safestrncpy(WFIFOP(fd, 94), msg_sd(sd, 300 + guild->checkcastles(g)), 16); // "'N' castles" + WFIFOL(fd, 110) = 0; // zeny +#else + safestrncpy(WFIFOP(fd, 70), msg_sd(sd, 300 + guild->checkcastles(g)), 16); // "'N' castles" + WFIFOL(fd, 86) = 0; // zeny + WFIFOL(fd, 90) = g->member[0].char_id; // leader +#endif - WFIFOSET(fd,packet_len(0x1b6)); + WFIFOSET(fd, packet_len(cmd)); } /// Guild alliance and opposition list (ZC_MYGUILD_BASIC_INFO). @@ -7504,35 +7595,47 @@ void clif_guild_memberlist(struct map_session_data *sd) int fd; int i,c; struct guild *g; +#if PACKETVER < 20161026 + const int cmd = 0x154; + const int size = 104; +#else + const int cmd = 0xaa5; + const int size = 34; +#endif + nullpo_retv(sd); - if( (fd = sd->fd) == 0 ) + if ((fd = sd->fd) == 0) return; - if( (g = sd->guild) == NULL ) + if ((g = sd->guild) == NULL) return; - WFIFOHEAD(fd, g->max_member * 104 + 4); - WFIFOW(fd, 0)=0x154; - for(i=0,c=0;i<g->max_member;i++){ - struct guild_member *m=&g->member[i]; - if(m->account_id==0) + WFIFOHEAD(fd, g->max_member * size + 4); + WFIFOW(fd, 0) = cmd; + for (i = 0, c = 0; i < g->max_member; i++) { + struct guild_member *m = &g->member[i]; + if (m->account_id == 0) continue; - WFIFOL(fd,c*104+ 4)=m->account_id; - WFIFOL(fd,c*104+ 8)=m->char_id; - WFIFOW(fd,c*104+12)=m->hair; - WFIFOW(fd,c*104+14)=m->hair_color; - WFIFOW(fd,c*104+16)=m->gender; - WFIFOW(fd,c*104+18)=m->class; - WFIFOW(fd,c*104+20)=m->lv; - WFIFOL(fd,c*104+22)=(int)cap_value(m->exp,0,INT32_MAX); - WFIFOL(fd,c*104+26)=m->online; - WFIFOL(fd,c*104+30)=m->position; - memset(WFIFOP(fd,c*104+34),0,50); //[Ind] - This is displayed in the 'note' column but being you can't edit it it's sent empty. - memcpy(WFIFOP(fd,c*104+84),m->name,NAME_LENGTH); + WFIFOL(fd, c * size + 4) = m->account_id; + WFIFOL(fd, c * size + 8) = m->char_id; + WFIFOW(fd, c * size + 12) = m->hair; + WFIFOW(fd, c * size + 14) = m->hair_color; + WFIFOW(fd, c * size + 16) = m->gender; + WFIFOW(fd, c * size + 18) = m->class; + WFIFOW(fd, c * size + 20) = m->lv; + WFIFOL(fd, c * size + 22) = (int)cap_value(m->exp, 0, INT32_MAX); + WFIFOL(fd, c * size + 26) = m->online; + WFIFOL(fd, c * size + 30) = m->position; +#if PACKETVER < 20161026 + memset(WFIFOP(fd, c * size + 34), 0, 50); //[Ind] - This is displayed in the 'note' column but being you can't edit it it's sent empty. + memcpy(WFIFOP(fd, c * size + 84), m->name, NAME_LENGTH); +#else + WFIFOL(fd, c * size + 34) = 0; // [4144] this is member last login time. But in hercules it not present. +#endif c++; } - WFIFOW(fd, 2)=c*104+4; - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOW(fd, 2) = c * size + 4; + WFIFOSET(fd, WFIFOW(fd, 2)); } /// Guild position name information (ZC_POSITION_ID_NAME_INFO). @@ -12953,13 +13056,22 @@ void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data *sd) _ void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data *sd) { int i; + int len = RFIFOW(fd, 2); if(!sd->state.gmaster_flag) return; + // Guild leadership change + if (len == 16 && RFIFOL(fd, 12) == 0) { + guild->gm_change(sd->status.guild_id, RFIFOL(fd, 8)); + return; + } + for(i=4;i<RFIFOW(fd,2);i+=12){ - guild->change_memberposition(sd->status.guild_id, - RFIFOL(fd,i),RFIFOL(fd,i+4),RFIFOL(fd,i+8)); + int position = RFIFOL(fd, i + 8); + if (position > 0) { + guild->change_memberposition(sd->status.guild_id, RFIFOL(fd, i), RFIFOL(fd, i + 4), position); + } } } @@ -19702,6 +19814,7 @@ void clif_defaults(void) { clif->party_created = clif_party_created; clif->party_member_info = clif_party_member_info; clif->party_info = clif_party_info; + clif->party_job_and_level = clif_party_job_and_level; clif->party_invite = clif_party_invite; clif->party_inviteack = clif_party_inviteack; clif->party_option = clif_party_option; diff --git a/src/map/clif.h b/src/map/clif.h index ccb227267..b34be81a3 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -917,6 +917,7 @@ struct clif_interface { void (*party_created) (struct map_session_data *sd,int result); void (*party_member_info) (struct party_data *p, struct map_session_data *sd); void (*party_info) (struct party_data* p, struct map_session_data *sd); + void (*party_job_and_level) (struct map_session_data *sd); void (*party_invite) (struct map_session_data *sd,struct map_session_data *tsd); void (*party_inviteack) (struct map_session_data* sd, const char* nick, int result); void (*party_option) (struct party_data *p,struct map_session_data *sd,int flag); diff --git a/src/map/date.c b/src/map/date.c index a20578e51..20ab9fe95 100644 --- a/src/map/date.c +++ b/src/map/date.c @@ -77,6 +77,13 @@ int date_get_sec(void) return lt->tm_sec; } +int date_get_dayofweek(void) +{ + time_t t = time(NULL); + struct tm *lt = localtime(&t); + return lt->tm_wday; +} + /*========================================== * Star gladiator related checks *------------------------------------------*/ diff --git a/src/map/date.h b/src/map/date.h index 3a109d1ad..ac0a3a7fa 100644 --- a/src/map/date.h +++ b/src/map/date.h @@ -31,6 +31,7 @@ int date_get_day(void); int date_get_hour(void); int date_get_min(void); int date_get_sec(void); +int date_get_dayofweek(void); bool is_day_of_sun(void); bool is_day_of_moon(void); diff --git a/src/map/guild.c b/src/map/guild.c index 6e5b1c539..838df3943 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -1814,23 +1814,28 @@ int guild_broken(int guild_id,int flag) } //Changes the Guild Master to the specified player. [Skotlex] -int guild_gm_change(int guild_id, struct map_session_data *sd) +int guild_gm_change(int guild_id, int char_id) { - struct guild *g; - nullpo_ret(sd); + struct guild *g = guild->search(guild_id); + char *name; + int i; - if (sd->status.guild_id != guild_id) - return 0; + nullpo_ret(g); - g=guild->search(guild_id); + ARR_FIND(0, MAX_GUILD, i, g->member[i].char_id == char_id); + + if (i == MAX_GUILD ) { + // Not part of the guild + return 0; + } - nullpo_ret(g); + name = g->member[i].name; - if (strcmp(g->master, sd->status.name) == 0) //Nothing to change. + if (strcmp(g->master, name) == 0) //Nothing to change. return 0; //Notify servers that master has changed. - intif->guild_change_gm(guild_id, sd->status.name, (int)strlen(sd->status.name)+1); + intif->guild_change_gm(guild_id, name, (int)strlen(name) + 1); return 1; } @@ -1864,6 +1869,7 @@ int guild_gm_changed(int guild_id, int account_id, int char_id) if (g->member[pos].sd && g->member[pos].sd->fd) { clif->message(g->member[pos].sd->fd, msg_sd(g->member[pos].sd,878)); //"You no longer are the Guild Master." g->member[pos].sd->state.gmaster_flag = 0; + clif->charnameack(0, &g->member[pos].sd->bl); } if (g->member[0].sd && g->member[0].sd->fd) { @@ -1871,6 +1877,7 @@ int guild_gm_changed(int guild_id, int account_id, int char_id) g->member[0].sd->state.gmaster_flag = 1; //Block his skills for 5 minutes to prevent abuse. guild->block_skill(g->member[0].sd, 300000); + clif->charnameack(0, &g->member[pos].sd->bl); } // announce the change to all guild members @@ -1880,6 +1887,7 @@ int guild_gm_changed(int guild_id, int account_id, int char_id) { clif->guild_basicinfo(g->member[i].sd); clif->guild_memberlist(g->member[i].sd); + clif->guild_belonginfo(g->member[i].sd, g); // Update clientside guildmaster flag } } diff --git a/src/map/guild.h b/src/map/guild.h index cdb28a37b..71e989870 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -141,7 +141,7 @@ struct guild_interface { int (*skillupack) (int guild_id,uint16 skill_id,int account_id); int (*dobreak) (struct map_session_data *sd, const char *name); int (*broken) (int guild_id,int flag); - int (*gm_change) (int guild_id, struct map_session_data *sd); + int (*gm_change) (int guild_id, int char_id); int (*gm_changed) (int guild_id, int account_id, int char_id); /* */ void (*castle_map_init) (void); diff --git a/src/map/npc.c b/src/map/npc.c index 2876ea595..a358fd2fb 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -2119,6 +2119,17 @@ int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_list, st script->cleararray_pc(sd, card_slot, (void*)0); } + for (j = 0; j < MAX_ITEM_OPTIONS; j++) { // Clear Each item option entry + key_opt_idx[j] = 0; + key_opt_value[j] = 0; + + snprintf(opt_index_str, sizeof(opt_index_str), "@slot_opt_idx%d", j + 1); + script->cleararray_pc(sd, opt_index_str, (void*)0); + + snprintf(opt_value_str, sizeof(opt_value_str), "@slot_opt_val%d", j + 1); + script->cleararray_pc(sd, opt_value_str, (void*)0); + } + // save list of to be sold items for (i = 0; i < VECTOR_LENGTH(*item_list); i++) { struct itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index 0bd85db7f..796ea577c 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -76,8 +76,10 @@ enum packet_headers { additemType = 0x2d4, #elif PACKETVER < 20150226 additemType = 0x990, -#else +#elif PACKETVER < 20160921 additemType = 0xa0c, +#else + additemType = 0xa37, #endif #if PACKETVER < 4 idle_unitType = 0x78, @@ -448,6 +450,10 @@ struct packet_additem { #if PACKETVER >= 20150226 struct ItemOptions option_data[MAX_ITEM_OPTIONS]; #endif +#if PACKETVER >= 20160921 + uint8 favorite; + uint16 look; +#endif } __attribute__((packed)); struct packet_dropflooritem { diff --git a/src/map/pc.c b/src/map/pc.c index 2303a83ca..a925b523c 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -750,6 +750,7 @@ int pc_setnewpc(struct map_session_data *sd, int account_id, int char_id, int lo return 0; } +// [4144] probably pc_equippoint should be replaced to pc_item_equippoint int pc_equippoint(struct map_session_data *sd,int n) { int ep = 0; @@ -782,6 +783,33 @@ int pc_equippoint(struct map_session_data *sd,int n) return ep; } +int pc_item_equippoint(struct map_session_data *sd, struct item_data* id) +{ + int ep = 0; + + nullpo_ret(sd); + nullpo_ret(id); + + if (!itemdb->isequip2(id)) + return 0; //Not equippable by players. + + ep = id->equip; + if (id->look == W_DAGGER || + id->look == W_1HSWORD || + id->look == W_1HAXE) { + if (pc->checkskill(sd, AS_LEFT) > 0 || + (sd->job & MAPID_UPPERMASK) == MAPID_ASSASSIN || + (sd->job & MAPID_UPPERMASK) == MAPID_KAGEROUOBORO) { + // Kagerou and Oboro can dual wield daggers. [Rytech] + if (ep == EQP_HAND_R) + return EQP_ARMS; + if (ep == EQP_SHADOW_WEAPON) + return EQP_SHADOW_ARMS; + } + } + return ep; +} + int pc_setinventorydata(struct map_session_data *sd) { int i; @@ -5090,9 +5118,8 @@ int pc_useitem(struct map_session_data *sd,int n) { clif->msgtable_num(sd, MSG_SECONDS_UNTIL_USE, delay_tick + 1); // [%d] seconds left until you can use #else char delay_msg[100]; - clif->msgtable_num(sd, MSG_SECONDS_UNTIL_USE, delay_tick + 1); // [%d] seconds left until you can use sprintf(delay_msg, msg_sd(sd, 26), delay_tick + 1); - clif->messagecolor_self(sd->fd, COLOR_YELLOW, delay_msg); + clif->messagecolor_self(sd->fd, COLOR_YELLOW, delay_msg); // [%d] seconds left until you can use #endif return 0; // Delay has not expired yet } @@ -8765,6 +8792,7 @@ int pc_jobchange(struct map_session_data *sd, int class, int upper) status_calc_pc(sd,SCO_FORCE); pc->checkallowskill(sd); pc->equiplookall(sd); + pc->update_job_and_level(sd); //if you were previously famous, not anymore. if (fame_flag != 0) { @@ -11923,6 +11951,24 @@ void pc_check_supernovice_call(struct map_session_data *sd, const char *message) } } +void pc_update_job_and_level(struct map_session_data *sd) +{ + nullpo_retv(sd); + + if (sd->status.party_id) { + struct party_data *p; + int i; + + if ((p = party->search(sd->status.party_id)) != NULL) { + ARR_FIND(0, MAX_PARTY, i, p->party.member[i].char_id == sd->status.char_id); + if (i < MAX_PARTY) { + p->party.member[i].lv = sd->status.base_level; + clif->party_job_and_level(sd); + } + } + } +} + void do_final_pc(void) { db_destroy(pc->itemcd_db); pc->at_db->destroy(pc->at_db,pc->autotrade_final); @@ -12044,6 +12090,7 @@ void pc_defaults(void) { pc->isequip = pc_isequip; pc->equippoint = pc_equippoint; + pc->item_equippoint = pc_item_equippoint; pc->setinventorydata = pc_setinventorydata; pc->checkskill = pc_checkskill; @@ -12264,6 +12311,7 @@ void pc_defaults(void) { pc->checkcombo = pc_checkcombo; pc->calcweapontype = pc_calcweapontype; pc->removecombo = pc_removecombo; + pc->update_job_and_level = pc_update_job_and_level; pc->bank_withdraw = pc_bank_withdraw; pc->bank_deposit = pc_bank_deposit; diff --git a/src/map/pc.h b/src/map/pc.h index af52f8946..04fd98b24 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -859,6 +859,7 @@ END_ZEROED_BLOCK; /* End */ int (*isequip) (struct map_session_data *sd,int n); int (*equippoint) (struct map_session_data *sd,int n); + int (*item_equippoint) (struct map_session_data *sd, struct item_data* id); int (*setinventorydata) (struct map_session_data *sd); int (*checkskill) (struct map_session_data *sd,uint16 skill_id); @@ -1095,6 +1096,7 @@ END_ZEROED_BLOCK; /* End */ bool (*db_checkid) (int class); void (*validate_levels) (void); + void (*update_job_and_level) (struct map_session_data *sd); /** * Autotrade persistency [Ind/Hercules <3] diff --git a/src/map/quest.c b/src/map/quest.c index ed8e5bd33..4e3362adb 100644 --- a/src/map/quest.c +++ b/src/map/quest.c @@ -103,22 +103,23 @@ int quest_pc_login(struct map_session_data *sd) * * New quest will be added as Q_ACTIVE. * - * @param sd Player's data - * @param quest_id ID of the quest to add. + * @param sd Player's data + * @param quest_id ID of the quest to add. + * @param time_limit Custom time, in UNIX epoch, for this quest * @return 0 in case of success, nonzero otherwise */ -int quest_add(struct map_session_data *sd, int quest_id) +int quest_add(struct map_session_data *sd, int quest_id, unsigned int time_limit) { int n; struct quest_db *qi = quest->db(quest_id); nullpo_retr(-1, sd); - if( qi == &quest->dummy ) { + if (qi == &quest->dummy) { ShowError("quest_add: quest %d not found in DB.\n", quest_id); return -1; } - if( quest->check(sd, quest_id, HAVEQUEST) >= 0 ) { + if (quest->check(sd, quest_id, HAVEQUEST) >= 0) { ShowError("quest_add: Character %d already has quest %d.\n", sd->status.char_id, quest_id); return -1; } @@ -130,7 +131,7 @@ int quest_add(struct map_session_data *sd, int quest_id) sd->avail_quests++; RECREATE(sd->quest_log, struct quest, sd->num_quests); - if( sd->avail_quests != sd->num_quests ) { + if (sd->avail_quests != sd->num_quests) { // The character has some completed quests, make room before them so that they will stay at the end of the array memmove(&sd->quest_log[n+1], &sd->quest_log[n], sizeof(struct quest)*(sd->num_quests-sd->avail_quests)); } @@ -138,7 +139,9 @@ int quest_add(struct map_session_data *sd, int quest_id) memset(&sd->quest_log[n], 0, sizeof(struct quest)); sd->quest_log[n].quest_id = qi->id; - if( qi->time ) + if (time_limit != 0) + sd->quest_log[n].time = time_limit; + else if (qi->time != 0) sd->quest_log[n].time = (unsigned int)(time(NULL) + qi->time); sd->quest_log[n].state = Q_ACTIVE; @@ -147,8 +150,8 @@ int quest_add(struct map_session_data *sd, int quest_id) clif->quest_add(sd, &sd->quest_log[n]); clif->quest_update_objective(sd, &sd->quest_log[n]); - if( map->save_settings&64 ) - chrif->save(sd,0); + if ((map->save_settings & 64) != 0) + chrif->save(sd, 0); return 0; } diff --git a/src/map/quest.h b/src/map/quest.h index 8837a1fb6..dda7c2c0a 100644 --- a/src/map/quest.h +++ b/src/map/quest.h @@ -69,7 +69,7 @@ struct quest_interface { /* */ struct quest_db *(*db) (int quest_id); int (*pc_login) (struct map_session_data *sd); - int (*add) (struct map_session_data *sd, int quest_id); + int (*add) (struct map_session_data *sd, int quest_id, unsigned int time_limit); int (*change) (struct map_session_data *sd, int qid1, int qid2); int (*delete) (struct map_session_data *sd, int quest_id); int (*update_objective_sub) (struct block_list *bl, va_list ap); diff --git a/src/map/script.c b/src/map/script.c index 4150d3adb..c23a335c3 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -30,6 +30,7 @@ #include "map/chat.h" #include "map/chrif.h" #include "map/clif.h" +#include "map/date.h" #include "map/elemental.h" #include "map/guild.h" #include "map/homunculus.h" @@ -7038,6 +7039,7 @@ BUILDIN(__setr) int64 num; const char* name; char prefix; + struct reg_db *ref; data = script_getdata(st,2); //datavalue = script_getdata(st,3); @@ -7050,11 +7052,11 @@ BUILDIN(__setr) num = reference_getuid(data); name = reference_getname(data); + ref = reference_getref(data); prefix = *name; if (not_server_variable(prefix)) { - sd = script->rid2sd(st); - if (sd == NULL) { + if (ref == NULL && (sd = script->rid2sd(st)) == NULL) { ShowError("script:set: no player attached for player variable '%s'\n", name); return true; } @@ -7102,9 +7104,9 @@ BUILDIN(__setr) } if (is_string_variable(name)) - script->set_reg(st, sd, num, name, script_getstr(st, 3), script_getref(st, 2)); + script->set_reg(st, sd, num, name, script_getstr(st, 3), ref); else - script->set_reg(st, sd, num, name, (const void *)h64BPTRSIZE(script_getnum(st, 3)), script_getref(st, 2)); + script->set_reg(st, sd, num, name, (const void *)h64BPTRSIZE(script_getnum(st, 3)), ref); return true; } @@ -10635,7 +10637,7 @@ BUILDIN(guildchangegm) if (sd == NULL) script_pushint(st,0); else - script_pushint(st,guild->gm_change(guild_id, sd)); + script_pushint(st, guild->gm_change(guild_id, sd->status.char_id)); return true; } @@ -13459,113 +13461,98 @@ BUILDIN(getequipcardcnt) /// Removes all cards from the item found in the specified equipment slot of the invoking character, /// and give them to the character. If any cards were removed in this manner, it will also show a success effect. -/// successremovecards <slot>; +/// successremovecards(<slot>); BUILDIN(successremovecards) { - int i=-1,c,cardflag=0; + int i = -1, c, cardflag = 0; struct map_session_data *sd = script->rid2sd(st); - int num = script_getnum(st,2); + int num = script_getnum(st, 2); if (sd == NULL) return true; if (num > 0 && num <= ARRAYLENGTH(script->equip)) - i=pc->checkequip(sd,script->equip[num-1]); + i = pc->checkequip(sd,script->equip[num - 1]); - if (i < 0 || !sd->inventory_data[i]) { + if (i < 0 || sd->inventory_data[i] == NULL) return true; - } - if(itemdb_isspecial(sd->status.inventory[i].card[0])) + if (itemdb_isspecial(sd->status.inventory[i].card[0])) return true; - for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c ) { - if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD ) {// extract this card from the item + for (c = sd->inventory_data[i]->slot - 1; c >= 0; --c) { + if (sd->status.inventory[i].card[c] > 0 && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD) { int flag; struct item item_tmp; - memset(&item_tmp,0,sizeof(item_tmp)); + + memset(&item_tmp, 0, sizeof(item_tmp)); + cardflag = 1; - item_tmp.nameid = sd->status.inventory[i].card[c]; + item_tmp.nameid = sd->status.inventory[i].card[c]; item_tmp.identify = 1; + sd->status.inventory[i].card[c] = 0; - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { - // get back the cart in inventory - clif->additem(sd,0,0,flag); + if ((flag = pc->additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT))) { + clif->additem(sd, 0, 0, flag); map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); } } } if (cardflag == 1) { - //if card was remove replace item with no card - int flag, j; - struct item item_tmp; - memset(&item_tmp,0,sizeof(item_tmp)); - - item_tmp.nameid = sd->status.inventory[i].nameid; - item_tmp.identify = 1; - item_tmp.refine = sd->status.inventory[i].refine; - item_tmp.attribute = sd->status.inventory[i].attribute; - item_tmp.expire_time = sd->status.inventory[i].expire_time; - item_tmp.bound = sd->status.inventory[i].bound; - - for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++) - item_tmp.card[j]=sd->status.inventory[i].card[j]; - - pc->delitem(sd, i, 1, 0, DELITEM_MATERIALCHANGE, LOG_TYPE_SCRIPT); - if ((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { - //chk if can be spawn in inventory otherwise put on floor - clif->additem(sd,0,0,flag); - map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); - } - + pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE); + clif->delitem(sd, i, 1, DELITEM_MATERIALCHANGE); + clif->additem(sd, i, 1, 0); + pc->equipitem(sd, i, sd->status.inventory[i].equip); clif->misceffect(&sd->bl,3); } return true; } /// Removes all cards from the item found in the specified equipment slot of the invoking character. -/// failedremovecards <slot>, <type>; +/// failedremovecards(<slot>, <type>); /// <type>=0 : will destroy both the item and the cards. /// <type>=1 : will keep the item, but destroy the cards. /// <type>=2 : will keep the cards, but destroy the item. -/// <type>=? : will just display the failure effect. +/// <type>=3 : will just display the failure effect. BUILDIN(failedremovecards) { - int i=-1,c,cardflag=0; + int i = -1, c, cardflag = 0; + int num = script_getnum(st, 2); + int typefail = script_getnum(st, 3); struct map_session_data *sd = script->rid2sd(st); - int num = script_getnum(st,2); - int typefail = script_getnum(st,3); if (sd == NULL) return true; if (num > 0 && num <= ARRAYLENGTH(script->equip)) - i=pc->checkequip(sd,script->equip[num-1]); + i = pc->checkequip(sd, script->equip[num - 1]); - if (i < 0 || !sd->inventory_data[i]) + if (i < 0 || sd->inventory_data[i] == NULL) return true; - if(itemdb_isspecial(sd->status.inventory[i].card[0])) + if (itemdb_isspecial(sd->status.inventory[i].card[0])) return true; - for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c ) { - if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD ) { + for (c = sd->inventory_data[i]->slot - 1; c >= 0; --c) { + if (sd->status.inventory[i].card[c] > 0 && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD) { cardflag = 1; - if(typefail == 2) {// add cards to inventory, clear + sd->status.inventory[i].card[c] = 0; + + if (typefail == 2) { // add cards to inventory, clear int flag; struct item item_tmp; - memset(&item_tmp,0,sizeof(item_tmp)); + memset(&item_tmp, 0, sizeof(item_tmp)); - item_tmp.nameid = sd->status.inventory[i].card[c]; + item_tmp.nameid = sd->status.inventory[i].card[c]; item_tmp.identify = 1; - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { - clif->additem(sd,0,0,flag); + if ((flag = pc->additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT))) { + clif->additem(sd, 0, 0, flag); map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); } } @@ -13573,35 +13560,16 @@ BUILDIN(failedremovecards) } if (cardflag == 1) { - if (typefail == 0 || typefail == 2) { - // destroy the item + if (typefail == 0 || typefail == 2) { // destroy the item pc->delitem(sd, i, 1, 0, DELITEM_FAILREFINE, LOG_TYPE_SCRIPT); } else if (typefail == 1) { - // destroy the card - int flag, j; - struct item item_tmp; - - memset(&item_tmp,0,sizeof(item_tmp)); - - item_tmp.nameid = sd->status.inventory[i].nameid; - item_tmp.identify = 1; - item_tmp.refine = sd->status.inventory[i].refine; - item_tmp.attribute = sd->status.inventory[i].attribute; - item_tmp.expire_time = sd->status.inventory[i].expire_time; - item_tmp.bound = sd->status.inventory[i].bound; - - for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++) - item_tmp.card[j]=sd->status.inventory[i].card[j]; - - pc->delitem(sd, i, 1, 0, DELITEM_FAILREFINE, LOG_TYPE_SCRIPT); - - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { - clif->additem(sd,0,0,flag); - map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); - } + pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE); + clif->delitem(sd, i, 1, DELITEM_MATERIALCHANGE); + clif->additem(sd, i, 1, 0); + pc->equipitem(sd, i, sd->status.inventory[i].equip); } - clif->misceffect(&sd->bl,2); } + clif->misceffect(&sd->bl, 2); return true; } @@ -14098,7 +14066,7 @@ BUILDIN(getequippedoptioninfo) /** * Gets the option information of an equipment. - * *getequipoptioninfo(<equip_index>,<slot>,<type>); + * *getequipoption(<equip_index>,<slot>,<type>); * * @param equip_index as the Index of the Equipment. * @param slot as the slot# of the Item Option (1 to MAX_ITEM_OPTIONS) @@ -14115,24 +14083,24 @@ BUILDIN(getequipoption) if (sd == NULL) { script_pushint(st, -1); - ShowError("buildin_getequipoptioninfo: Player not attached!\n"); + ShowError("buildin_getequipoption: Player not attached!\n"); return false; } if (slot <= 0 || slot > MAX_ITEM_OPTIONS) { script_pushint(st, -1); - ShowError("buildin_getequipoptioninfo: Invalid option slot %d (Min: 1, Max: %d) provided.\n", slot, MAX_ITEM_OPTIONS); + ShowError("buildin_getequipoption: Invalid option slot %d (Min: 1, Max: %d) provided.\n", slot, MAX_ITEM_OPTIONS); return false; } if (equip_index > 0 && equip_index <= ARRAYLENGTH(script->equip)) { if ((i = pc->checkequip(sd, script->equip[equip_index - 1])) == -1) { - ShowError("buildin_getequipoptioninfo: No equipment is equipped in the given index %d.\n", equip_index); + ShowError("buildin_getequipoption: No equipment is equipped in the given index %d.\n", equip_index); script_pushint(st, -1); return false; } } else { - ShowError("buildin_getequipoptioninfo: Invalid equipment index %d provided.\n", equip_index); + ShowError("buildin_getequipoption: Invalid equipment index %d provided.\n", equip_index); script_pushint(st, 0); return false; } @@ -14146,7 +14114,7 @@ BUILDIN(getequipoption) val = sd->status.inventory[i].option[slot-1].value; break; default: - ShowError("buildin_geteqiupoptioninfo: Invalid option data type %d provided.\n", opt_type); + ShowError("buildin_getequipoption: Invalid option data type %d provided.\n", opt_type); script_pushint(st, -1); break; } @@ -15043,22 +15011,62 @@ BUILDIN(dispbottom) * All The Players Full Recovery * (HP/SP full restore and resurrect if need) *------------------------------------------*/ +int buildin_recovery_sub(struct map_session_data *sd) +{ + nullpo_retr(0, sd); + + if (pc_isdead(sd)) { + status->revive(&sd->bl, 100, 100); + } else { + status_percent_heal(&sd->bl, 100, 100); + } + + return 0; +} + +int buildin_recovery_pc_sub(struct map_session_data *sd, va_list ap) +{ + return script->buildin_recovery_sub(sd); +} + +int buildin_recovery_bl_sub(struct block_list *bl, va_list ap) +{ + return script->buildin_recovery_sub(BL_CAST(BL_PC, bl)); +} + BUILDIN(recovery) { - struct map_session_data *sd; - struct s_mapiterator* iter; + if (script_hasdata(st, 2)) { + if (script_isstringtype(st, 2)) { + int16 m = map->mapname2mapid(script_getstr(st, 2)); - iter = mapit_getallusers(); - for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) { - if(pc_isdead(sd)) - status->revive(&sd->bl, 100, 100); - else - status_percent_heal(&sd->bl, 100, 100); - clif->message(sd->fd,msg_sd(sd,880)); // "You have been recovered!" + if (m == -1) { + ShowWarning("script:recovery: invalid map!\n"); + return false; + } + + if (script_hasdata(st, 6)) { + int16 x1 = script_getnum(st, 3); + int16 y1 = script_getnum(st, 4); + int16 x2 = script_getnum(st, 5); + int16 y2 = script_getnum(st, 6); + map->foreachinarea(script->buildin_recovery_bl_sub, m, x1, y1, x2, y2, BL_PC); + } else { + map->foreachinmap(script->buildin_recovery_bl_sub, m, BL_PC); + } + } else { + struct map_session_data *sd = script->id2sd(st, script_getnum(st, 2)); + + if (sd != NULL) { + script->buildin_recovery_sub(sd); + } + } + } else { + map->foreachpc(script->buildin_recovery_pc_sub); } - mapit->free(iter); return true; } + /*========================================== * Get your pet info: getpetinfo(n) * n -> 0:pet_id 1:pet_class 2:pet_name @@ -16211,6 +16219,60 @@ BUILDIN(isstr) return true; } +enum datatype { + DATATYPE_NIL = 1 << 7, // we don't start at 1, to leave room for primitives + DATATYPE_STR = 1 << 8, + DATATYPE_INT = 1 << 9, + DATATYPE_CONST = 1 << 10, + DATATYPE_PARAM = 1 << 11, + DATATYPE_VAR = 1 << 12, + DATATYPE_LABEL = 1 << 13, +}; + +BUILDIN(getdatatype) { + int type; + + if (script_hasdata(st, 2)) { + struct script_data *data = script_getdata(st, 2); + + if (data_isstring(data)) { + type = DATATYPE_STR; + if (data->type == C_CONSTSTR) { + type |= DATATYPE_CONST; + } + } else if (data_isint(data)) { + type = DATATYPE_INT; + } else if (data_islabel(data)) { + type = DATATYPE_LABEL; + } else if (data_isreference(data)) { + if (reference_toconstant(data)) { + type = DATATYPE_CONST | DATATYPE_INT; + } else if (reference_toparam(data)) { + type = DATATYPE_PARAM | DATATYPE_INT; + } else if (reference_tovariable(data)) { + type = DATATYPE_VAR; + if (is_string_variable(reference_getname(data))) { + type |= DATATYPE_STR; + } else { + type |= DATATYPE_INT; + } + } else { + ShowError("script:getdatatype: Unknown reference type!\n"); + script->reportdata(data); + st->state = END; + return false; + } + } else { + type = data->type; // fallback to primitive type if unknown + } + } else { + type = DATATYPE_NIL; // nothing was passed + } + + script_pushint(st, type); + return true; +} + //======================================================= // chr <int> //------------------------------------------------------- @@ -17032,6 +17094,7 @@ BUILDIN(swap) { struct map_session_data *sd = NULL; struct script_data *data1, *data2; + struct reg_db *ref1, *ref2; const char *varname1, *varname2; int64 uid1, uid2; @@ -17072,6 +17135,8 @@ BUILDIN(swap) uid1 = reference_getuid(data1); uid2 = reference_getuid(data2); + ref1 = reference_getref(data1); + ref2 = reference_getref(data2); if (is_string_variable(varname1)) { const char *value1, *value2; @@ -17080,8 +17145,8 @@ BUILDIN(swap) value2 = script_getstr(st,3); if (strcmpi(value1, value2)) { - script->set_reg(st, sd, uid1, varname1, value2, script_getref(st,3)); - script->set_reg(st, sd, uid2, varname2, value1, script_getref(st,2)); + script->set_reg(st, sd, uid1, varname1, value2, ref1); + script->set_reg(st, sd, uid2, varname2, value1, ref2); } } else { @@ -17091,8 +17156,8 @@ BUILDIN(swap) value2 = script_getnum(st,3); if (value1 != value2) { - script->set_reg(st, sd, uid1, varname1, (const void *)h64BPTRSIZE(value2), script_getref(st,3)); - script->set_reg(st, sd, uid2, varname2, (const void *)h64BPTRSIZE(value1), script_getref(st,2)); + script->set_reg(st, sd, uid1, varname1, (const void *)h64BPTRSIZE(value2), ref1); + script->set_reg(st, sd, uid2, varname2, (const void *)h64BPTRSIZE(value1), ref2); } } return true; @@ -20273,19 +20338,21 @@ BUILDIN(setquest) { unsigned short i; int quest_id; + unsigned int time_limit; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; quest_id = script_getnum(st, 2); + time_limit = script_hasdata(st, 3) ? script_getnum(st, 3) : 0; - quest->add(sd, quest_id); + quest->add(sd, quest_id, time_limit); // If questinfo is set, remove quest bubble once quest is set. - for(i = 0; i < map->list[sd->bl.m].qi_count; i++) { + for (i = 0; i < map->list[sd->bl.m].qi_count; i++) { struct questinfo *qi = &map->list[sd->bl.m].qi_data[i]; - if( qi->quest_id == quest_id ) { + if (qi->quest_id == quest_id) { #if PACKETVER >= 20120410 clif->quest_show_event(sd, &qi->nd->bl, 9999, 0); #else @@ -23148,6 +23215,100 @@ BUILDIN(mergeitem) return true; } +// getcalendartime(<day of month>, <day of week>{, <hour>{, <minute>}}); +// Returns the UNIX Timestamp of next ocurrency of given time +BUILDIN(getcalendartime) +{ + struct tm info = { 0 }; + int day_of_month = script_hasdata(st, 4) ? script_getnum(st, 4) : -1; + int day_of_week = script_hasdata(st, 5) ? script_getnum(st, 5) : -1; + int year = date_get_year(); + int month = date_get_month(); + int day = date_get_day(); + int cur_hour = date_get_hour(); + int cur_min = date_get_min(); + int hour = script_getnum(st, 2); + int minute = script_getnum(st, 3); + + info.tm_sec = 0; + info.tm_min = minute; + info.tm_hour = hour; + info.tm_mday = day; + info.tm_mon = month - 1; + info.tm_year = year - 1900; + + if (day_of_month > -1 && day_of_week > -1) { + ShowError("script:getcalendartime: You must only specify a day_of_week or a day_of_month, not both\n"); + script_pushint(st, -1); + return false; + } + if (day_of_month > -1 && (day_of_month < 1 || day_of_month > 31)) { + ShowError("script:getcalendartime: Day of Month in invalid range. Must be between 1 and 31.\n"); + script_pushint(st, -1); + return false; + } + if (day_of_week > -1 && (day_of_week < 0 || day_of_week > 6)) { + ShowError("script:getcalendartime: Day of Week in invalid range. Must be between 0 and 6.\n"); + script_pushint(st, -1); + return false; + } + if (hour > -1 && (hour > 23)) { + ShowError("script:getcalendartime: Hour in invalid range. Must be between 0 and 23.\n"); + script_pushint(st, -1); + return false; + } + if (minute > -1 && (minute > 59)) { + ShowError("script:getcalendartime: Minute in invalid range. Must be between 0 and 59.\n"); + script_pushint(st, -1); + return false; + } + if (hour == -1 || minute == -1) { + ShowError("script:getcalendartime: Minutes and Hours are required\n"); + script_pushint(st, -1); + return false; + } + + if (day_of_month > -1) { + if (day_of_month < day) { // Next Month + info.tm_mon++; + } else if (day_of_month == day) { // Today + if (hour < cur_hour || (hour == cur_hour && minute < cur_min)) { // But past time, next month + info.tm_mon++; + } + } + + // Loops until month has finding a month that has day_of_month + do { + time_t t; + struct tm *lt; + info.tm_mday = day_of_month; + t = mktime(&info); + lt = localtime(&t); + info = *lt; + } while (info.tm_mday != day_of_month); + } else if (day_of_week > -1) { + int cur_wday = date_get_dayofweek(); + + if (day_of_week > cur_wday) { // This week + info.tm_mday += (day_of_week - cur_wday); + } else if (day_of_week == cur_wday) { // Today + if (hour < cur_hour || (hour == cur_hour && minute <= cur_min)) { + info.tm_mday += 7; // Next week + } + } else if (day_of_week < cur_wday) { // Next week + info.tm_mday += (7 - cur_wday + day_of_week); + } + } else if (day_of_week == -1 && day_of_month == -1) { // Next occurence of hour/min + if (hour < cur_hour || (hour == cur_hour && minute < cur_min)) { + info.tm_mday++; + } + } + + script_pushint(st, mktime(&info)); + + return true; +} + /** place holder for the translation macro **/ BUILDIN(_) { @@ -23643,7 +23804,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(pcre_match,"ss"), BUILDIN_DEF(dispbottom,"s?"), //added from jA [Lupus] BUILDIN_DEF(getusersname,""), - BUILDIN_DEF(recovery,""), + BUILDIN_DEF(recovery,"?????"), BUILDIN_DEF(getpetinfo,"i"), BUILDIN_DEF(gethominfo,"i"), BUILDIN_DEF(getmercinfo,"i?"), @@ -23654,6 +23815,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(charisalpha,"si"), //isalpha [Valaris] BUILDIN_DEF(charat,"si"), BUILDIN_DEF(isstr,"v"), + BUILDIN_DEF(getdatatype, "?"), BUILDIN_DEF(chr,"i"), BUILDIN_DEF(ord,"s"), BUILDIN_DEF(setchar,"ssi"), @@ -23856,7 +24018,7 @@ void script_parse_builtin(void) { //Quest Log System [Inkfish] BUILDIN_DEF(questinfo, "ii??"), - BUILDIN_DEF(setquest, "i"), + BUILDIN_DEF(setquest, "i?"), BUILDIN_DEF(erasequest, "i?"), BUILDIN_DEF(completequest, "i?"), BUILDIN_DEF(questprogress, "i?"), @@ -23908,6 +24070,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(removechannelhandler, "ss"), BUILDIN_DEF(showscript, "s?"), BUILDIN_DEF(mergeitem,""), + BUILDIN_DEF(getcalendartime, "ii??"), BUILDIN_DEF(_,"s"), BUILDIN_DEF2(_, "_$", "s"), }; @@ -24127,6 +24290,15 @@ void script_hardcoded_constants(void) script->set_constant("PERM_DISABLE_EXP", PC_PERM_DISABLE_EXP, false, false); script->set_constant("PERM_DISABLE_SKILL_USAGE", PC_PERM_DISABLE_SKILL_USAGE, false, false); + script->constdb_comment("Data types"); + script->set_constant("DATATYPE_NIL", DATATYPE_NIL, false, false); + script->set_constant("DATATYPE_STR", DATATYPE_STR, false, false); + script->set_constant("DATATYPE_INT", DATATYPE_INT, false, false); + script->set_constant("DATATYPE_CONST", DATATYPE_CONST, false, false); + script->set_constant("DATATYPE_PARAM", DATATYPE_PARAM, false, false); + script->set_constant("DATATYPE_VAR", DATATYPE_VAR, false, false); + script->set_constant("DATATYPE_LABEL", DATATYPE_LABEL, false, false); + script->constdb_comment("Renewal"); #ifdef RENEWAL script->set_constant("RENEWAL", 1, false, false); @@ -24379,6 +24551,9 @@ void script_defaults(void) script->db_free_code_sub = db_script_free_code_sub; script->add_autobonus = script_add_autobonus; script->menu_countoptions = menu_countoptions; + script->buildin_recovery_sub = buildin_recovery_sub; + script->buildin_recovery_pc_sub = buildin_recovery_pc_sub; + script->buildin_recovery_bl_sub = buildin_recovery_bl_sub; script->buildin_areawarp_sub = buildin_areawarp_sub; script->buildin_areapercentheal_sub = buildin_areapercentheal_sub; script->buildin_delitem_delete = buildin_delitem_delete; diff --git a/src/map/script.h b/src/map/script.h index fddcf4908..189122230 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -854,6 +854,9 @@ struct script_interface { int (*db_free_code_sub) (union DBKey key, struct DBData *data, va_list ap); void (*add_autobonus) (const char *autobonus); int (*menu_countoptions) (const char *str, int max_count, int *total); + int (*buildin_recovery_sub) (struct map_session_data *sd); + int (*buildin_recovery_pc_sub) (struct map_session_data *sd, va_list ap); + int (*buildin_recovery_bl_sub) (struct block_list *bl, va_list ap); int (*buildin_areawarp_sub) (struct block_list *bl, va_list ap); int (*buildin_areapercentheal_sub) (struct block_list *bl, va_list ap); void (*buildin_delitem_delete) (struct map_session_data *sd, int idx, int *amount, bool delete_items); |