From f3edaa82a300e9d397337b8f815c7903c239497b Mon Sep 17 00:00:00 2001 From: zephyrus Date: Thu, 28 Feb 2008 22:25:58 +0000 Subject: - Added cash shop support. (i need to add documentation, working on it). - An charcommand is still required to add/remove points. - Scripts command only requires to work on #CASHPOINTS and #KAFRAPOINTS. - I called it "Kafra Points" just because it's how comes in the translation. I allready know this changes between Oficial servers. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12264 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/clif.c | 52 +++++++++++++++++++++++++++ src/map/clif.h | 2 ++ src/map/map.h | 4 ++- src/map/npc.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/map/npc.h | 2 ++ src/map/pc.c | 63 +++++++++++++++++++++++++++++++++ src/map/pc.h | 4 +++ 7 files changed, 226 insertions(+), 10 deletions(-) (limited to 'src/map') diff --git a/src/map/clif.c b/src/map/clif.c index c51e2b0df..4ce9ff3c4 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -11701,6 +11701,57 @@ void clif_parse_Mail_send(int fd, struct map_session_data *sd) #endif +/*========================================== + * CASH/POINT SHOP + *==========================================*/ +void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd) +{ + int fd,i; + + nullpo_retv(sd); + nullpo_retv(nd); + + fd = sd->fd; + sd->npc_shopid = nd->bl.id; + WFIFOHEAD(fd, 200 * 11 + 12); + WFIFOW(fd,0) = 0x287; + WFIFOW(fd,2) = 12 + nd->u.shop.count*11; + WFIFOL(fd,4) = sd->cashPoints; // Cash Points + WFIFOL(fd,8) = sd->kafraPoints; // Kafra Points + + for( i = 0; i < nd->u.shop.count; i++ ) + { + struct item_data* id = itemdb_search(nd->u.shop.shop_item[i].nameid); + WFIFOL(fd,12+i*11) = nd->u.shop.shop_item[i].value; + WFIFOL(fd,16+i*11) = nd->u.shop.shop_item[i].value; // Discount Prize? Maybe a Discount item + WFIFOB(fd,20+i*11) = itemtype(id->type); + WFIFOW(fd,21+i*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid; + } + WFIFOSET(fd,WFIFOW(fd,2)); +} + +void clif_parse_cashshop_buy(int fd, struct map_session_data *sd) +{ + int fail = 0, amount, points; + short nameid; + struct npc_data *nd; + nullpo_retv(sd); + + nd = (struct npc_data *)map_id2bl(sd->npc_shopid); + nameid = RFIFOW(fd,2); + amount = RFIFOW(fd,4); + points = RFIFOL(fd,6); // Not Implemented. Should be 0 + + fail = npc_cashshop_buy(sd, nameid, amount, points); + + WFIFOHEAD(fd,12); + WFIFOW(fd,0) = 0x289; + WFIFOL(fd,2) = sd->cashPoints; + WFIFOL(fd,6) = sd->kafraPoints; + WFIFOW(fd,10) = fail; + WFIFOSET(fd,12); +} + /*========================================== * Requesting equip of a player *------------------------------------------*/ @@ -12161,6 +12212,7 @@ static int packetdb_readdb(void) {clif_parse_Mail_winopen,"mailwinopen"}, {clif_parse_Mail_send,"mailsend"}, #endif + {clif_parse_cashshop_buy,"cashshopbuy"}, {clif_parse_ViewPlayerEquip,"viewplayerequip"}, {clif_parse_EquipTick,"equiptickbox"}, {NULL,NULL} diff --git a/src/map/clif.h b/src/map/clif.h index c750e42d2..1aa5edcf6 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -411,4 +411,6 @@ void clif_Mail_refreshinbox(struct map_session_data *sd); void clif_Mail_getattachment(int fd, uint8 flag); #endif +void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd); + #endif /* _CLIF_H_ */ diff --git a/src/map/map.h b/src/map/map.h index 1d286191d..72f869f4e 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -188,7 +188,7 @@ enum bl_type { #define BL_CHAR (BL_PC|BL_MOB|BL_HOM) #define BL_ALL 0xfff -enum npc_subtype { WARP, SHOP, SCRIPT }; +enum npc_subtype { WARP, SHOP, SCRIPT, CASHSHOP }; enum { RC_FORMLESS=0, @@ -782,6 +782,8 @@ struct map_session_data { char away_message[128]; // [LuzZza] + int cashPoints, kafraPoints; + // Mail System [Zephyrus] struct { short nameid; diff --git a/src/map/npc.c b/src/map/npc.c index b7b62898f..37b8d99b8 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -932,6 +932,9 @@ int npc_click(struct map_session_data* sd, struct npc_data* nd) case SHOP: clif_npcbuysell(sd,nd->bl.id); break; + case CASHSHOP: + clif_cashshop_show(sd,nd); + break; case SCRIPT: run_script(nd->u.scr.script,0,sd->bl.id,nd->bl.id); break; @@ -1012,6 +1015,77 @@ static int npc_buylist_sub(struct map_session_data* sd, int n, unsigned short* i npc_event(sd, npc_ev, 0); return 0; } +/*========================================== + * Cash Shop Buy + *------------------------------------------*/ +int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int points) +{ + struct npc_data *nd = (struct npc_data *)map_id2bl(sd->npc_shopid); + struct item_data *item; + int i, prize, w; + + if( !nd || nd->subtype != CASHSHOP ) + return 1; + + if( sd->state.trading ) + return 4; + + if( (item = itemdb_search(nameid)) == NULL ) + return 5; // Invalid Item + + ARR_FIND(0, nd->u.shop.count, i, nd->u.shop.shop_item[i].nameid == nameid); + if( i == nd->u.shop.count ) + return 5; + if( nd->u.shop.shop_item[i].value <= 0 ) + return 5; + + if(!itemdb_isstackable(nameid) && amount > 1) + { + ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %d!\n", + sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid); + amount = 1; + } + + switch( pc_checkadditem(sd, nameid, amount) ) + { + case ADDITEM_NEW: + if( pc_inventoryblank(sd) == 0 ) + return 3; + break; + case ADDITEM_OVERAMOUNT: + return 3; + } + + w = item->weight * amount; + if( w + sd->weight > sd->max_weight ) + return 3; + + prize = nd->u.shop.shop_item[i].value * amount; + if( points > prize ) + points = prize; + + if( sd->cashPoints < prize - points ) + return 6; + if( sd->kafraPoints < points ) + return 6; + + pc_paycash(sd, prize, points); + + if( !pet_create_egg(sd, nameid) ) + { + struct item item_tmp; + memset(&item_tmp, 0, sizeof(struct item)); + item_tmp.nameid = nameid; + item_tmp.identify = 1; + + pc_additem(sd,&item_tmp, amount); + } + + if(log_config.enable_logs&0x20) + log_pick_pc(sd, "S", nameid, amount, NULL); + + return 0; +} /*========================================== * @@ -1266,7 +1340,7 @@ int npc_unload(struct npc_data* nd) npc_chat_finalize(nd); // deallocate npc PCRE data structures #endif - if( nd->subtype == SHOP ) + if( nd->subtype == SHOP || nd->subtype == CASHSHOP ) aFree(nd->u.shop.shop_item); else if( nd->subtype == SCRIPT ) @@ -1547,7 +1621,7 @@ static const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const return strchr(start,'\n');// continue } -/// Parses a shop npc. +/// Parses a shop/cashshop npc. static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) { //TODO: could be rewritten to NOT need this temp array [ultramage] @@ -1557,12 +1631,17 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const int x, y, dir, m, i; struct npc_data *nd; + enum npc_subtype type = SHOP; + if( !strcasecmp(w2,"cashshop") ) + type = CASHSHOP; + if( strcmp(w1,"-") == 0 ) {// 'floating' shop? - x = 0; y = 0; dir = 0; m = -1; + x = y = dir = 0; + m = -1; } else - {// w1=,,, + { char mapname[32]; if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 || strchr(w4, ',') == NULL ) @@ -1570,6 +1649,7 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const ShowError("npc_parse_shop: Invalid shop definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); return strchr(start,'\n');// skip and continue } + m = map_mapname2mapid(mapname); } @@ -1583,14 +1663,25 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const ShowError("npc_parse_shop: Invalid item definition in file '%s', line '%d'. Ignoring the rest of the line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); break; } - id = itemdb_search(nameid); + + if( (id = itemdb_search(nameid)) == NULL ) + { + ShowError("npc_parse_shop: Invalid sell item in file '%s', line '%d'. Ignoring the rest of the line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + break; + } + if( value < 0 ) - value = id->value_buy; - if( value*0.75 < id->value_sell*1.24 ) + { + if( type == SHOP ) value = id->value_buy; + else value = 0; // Cashshop don't have a "buy prize" in the item_db + } + + if( type == SHOP && value*0.75 < id->value_sell*1.24 ) {// Expoit possible: you can buy and sell back with profit ShowWarning("npc_parse_shop: Item %s [%d] discounted buying price (%d->%d) is less than overcharged selling price (%d->%d) at file '%s', line '%d'.\n", id->name, nameid, value, (int)(value*0.75), id->value_sell, (int)(id->value_sell*1.24), filepath, strline(buffer,start-buffer)); } + //for logs filters, atcommands and iteminfo script command if( id->maxchance <= 0 ) id->maxchance = 10000; //10000 (100% drop chance)would show that the item's sold in NPC Shop @@ -1620,7 +1711,7 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const ++npc_shop; nd->bl.type = BL_NPC; - nd->subtype = SHOP; + nd->subtype = type; if( m >= 0 ) {// normal shop npc map_addnpc(m,nd); @@ -2605,7 +2696,7 @@ void npc_parsesrcfile(const char* filepath) { p = npc_parse_warp(w1,w2,w3,w4, p, buffer, filepath); } - else if( strcasecmp(w2,"shop") == 0 && count > 3 ) + else if( (!strcasecmp(w2,"shop") || !strcasecmp(w2,"cashshop")) && count > 3 ) { p = npc_parse_shop(w1,w2,w3,w4, p, buffer, filepath); } diff --git a/src/map/npc.h b/src/map/npc.h index 087d34d40..25487e7ff 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -89,6 +89,8 @@ int npc_reload(void); void npc_read_event_script(void); int npc_script_event(struct map_session_data* sd, enum npce_event type); +int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int points); + extern struct npc_data* fake_nd; #endif /* _NPC_H_ */ diff --git a/src/map/pc.c b/src/map/pc.c index 0dbc8c076..551fa9c55 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -792,6 +792,10 @@ int pc_reg_received(struct map_session_data *sd) sd->change_level = pc_readglobalreg(sd,"jobchange_level"); sd->die_counter = pc_readglobalreg(sd,"PC_DIE_COUNTER"); + // Cash shop + sd->cashPoints = pc_readaccountreg(sd,"#CASHPOINTS"); + sd->kafraPoints = pc_readaccountreg(sd,"#KAFRAPOINTS"); + if ((sd->class_&MAPID_BASEMASK)==MAPID_TAEKWON) { //Better check for class rather than skill to prevent "skill resets" from unsetting this sd->mission_mobid = pc_readglobalreg(sd,"TK_MISSION_ID"); @@ -2694,6 +2698,65 @@ int pc_payzeny(struct map_session_data *sd,int zeny) return 0; } +/*========================================== + * Cash Shop + *------------------------------------------*/ + +void pc_paycash(struct map_session_data *sd, int prize, int points) +{ + char output[128]; + int cash = prize - points; + nullpo_retv(sd); + + sd->cashPoints -= cash; + sd->kafraPoints -= points; + + pc_setaccountreg(sd,"#CASHPOINTS",sd->cashPoints); + pc_setaccountreg(sd,"#KAFRAPOINTS",sd->kafraPoints); + + if( points ) + { + sprintf(output, "Used %d kafra points. %d points remaining.", points, sd->kafraPoints); + clif_disp_onlyself(sd, output, strlen(output)); + } + + if( cash ) + { + sprintf(output, "Used %d cash points. %d points remaining.", cash, sd->cashPoints); + clif_disp_onlyself(sd, output, strlen(output)); + } +} + +void pc_getcash(struct map_session_data *sd, int cash, int points) +{ + char output[128]; + nullpo_retv(sd); + + if( cash > MAX_ZENY - sd->cashPoints ) + cash = MAX_ZENY - sd->cashPoints; + + sd->cashPoints += cash; + + if( points > MAX_ZENY - sd->kafraPoints ) + points = MAX_ZENY - sd->kafraPoints; + + sd->kafraPoints += points; + + pc_setaccountreg(sd,"#CASHPOINTS",sd->cashPoints); + pc_setaccountreg(sd,"#KAFRAPOINTS",sd->kafraPoints); + + if( cash > 0 ) + { + sprintf(output, "Gained %d cash points. Total %d points", points, sd->cashPoints); + clif_disp_onlyself(sd, output, strlen(output)); + } + + if( points > 0 ) + { + sprintf(output, "Gained %d kafra points. Total %d points", points, sd->kafraPoints); + clif_disp_onlyself(sd, output, strlen(output)); + } +} /*========================================== * お金を得る diff --git a/src/map/pc.h b/src/map/pc.h index 2d96b1f31..d754034b1 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -177,6 +177,10 @@ int pc_additem(struct map_session_data*,struct item*,int); int pc_getzeny(struct map_session_data*,int); int pc_delitem(struct map_session_data*,int,int,int); +// Special Shop System +void pc_paycash(struct map_session_data *sd, int prize, int points); +void pc_getcash(struct map_session_data *sd, int cash, int points); + int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amount); int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type); int pc_putitemtocart(struct map_session_data *sd,int idx,int amount); -- cgit v1.2.3-70-g09d2