summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
authorzephyrus <zephyrus@54d463be-8e91-2dee-dedb-b68131a5f0ec>2008-11-16 16:14:30 +0000
committerzephyrus <zephyrus@54d463be-8e91-2dee-dedb-b68131a5f0ec>2008-11-16 16:14:30 +0000
commit8d5fe8a2562df4eb5e6eca2fb161514d9f6a7e9d (patch)
tree8d024104aa15ed6c2aa5070bd03ed7790a2afd90 /src/map
parent9b1e41499d17bb424414a7821e74a53c6d3e3f74 (diff)
downloadhercules-8d5fe8a2562df4eb5e6eca2fb161514d9f6a7e9d.tar.gz
hercules-8d5fe8a2562df4eb5e6eca2fb161514d9f6a7e9d.tar.bz2
hercules-8d5fe8a2562df4eb5e6eca2fb161514d9f6a7e9d.tar.xz
hercules-8d5fe8a2562df4eb5e6eca2fb161514d9f6a7e9d.zip
- Item Rental System.
Script Usage: - rentitem <itemid>,<seconds>; - rentitem <itemname>,<seconds>; git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@13370 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src/map')
-rw-r--r--src/map/clif.c45
-rw-r--r--src/map/clif.h4
-rw-r--r--src/map/mail.c14
-rw-r--r--src/map/pc.c115
-rw-r--r--src/map/pc.h6
-rw-r--r--src/map/script.c76
-rw-r--r--src/map/storage.c35
-rw-r--r--src/map/trade.c7
-rw-r--r--src/map/unit.c1
9 files changed, 263 insertions, 40 deletions
diff --git a/src/map/clif.c b/src/map/clif.c
index 0a4200396..81902f4e4 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -1419,17 +1419,22 @@ int clif_selllist(struct map_session_data *sd)
fd=sd->fd;
WFIFOHEAD(fd, MAX_INVENTORY * 10 + 4);
WFIFOW(fd,0)=0xc7;
- for(i=0;i<MAX_INVENTORY;i++) {
- if(sd->status.inventory[i].nameid > 0 && sd->inventory_data[i]) {
- if (!itemdb_cansell(&sd->status.inventory[i], pc_isGM(sd)))
+ for( i = 0; i < MAX_INVENTORY; i++ )
+ {
+ if( sd->status.inventory[i].nameid > 0 && sd->inventory_data[i] )
+ {
+ if( !itemdb_cansell(&sd->status.inventory[i], pc_isGM(sd)) )
continue;
+ if( sd->status.inventory[i].expire_time )
+ continue; // Cannot Sell Rental Items
+
val=sd->inventory_data[i]->value_sell;
- if (val < 0)
+ if( val < 0 )
continue;
WFIFOW(fd,4+c*10)=i+2;
WFIFOL(fd,6+c*10)=val;
- if (!sd->inventory_data[i]->flag.value_notoc)
+ if( !sd->inventory_data[i]->flag.value_notoc )
val=pc_modifysellvalue(sd,val);
WFIFOL(fd,10+c*10)=val;
c++;
@@ -11992,12 +11997,12 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd)
return;
}
- if( !pc_candrop(sd, &sd->status.inventory[idx]) || !sd->status.inventory[idx].identify )
+ if( !pc_candrop(sd, &sd->status.inventory[idx]) || !sd->status.inventory[idx].identify || sd->status.inventory[idx].expire_time )
{ // Quest Item or something else
clif_Auction_setitem(sd->fd, idx, true);
return;
}
-
+
sd->auction.index = idx;
sd->auction.amount = amount;
clif_Auction_setitem(fd, idx + 2, false);
@@ -12207,7 +12212,10 @@ void clif_parse_cashshop_buy(int fd, struct map_session_data *sd)
amount = RFIFOW(fd,4);
points = RFIFOL(fd,6); // Not Implemented. Should be 0
- fail = npc_cashshop_buy(sd, nameid, amount, points);
+ if( sd->state.trading || !sd->npc_shopid )
+ fail = 1;
+ else
+ fail = npc_cashshop_buy(sd, nameid, amount, points);
WFIFOHEAD(fd,12);
WFIFOW(fd,0) = 0x289;
@@ -12636,6 +12644,27 @@ void clif_mercenary_message(int fd, int message)
WFIFOSET(fd,4);
}
+/*------------------------------------------
+ * Rental System Messages
+ *------------------------------------------*/
+void clif_rental_time(int fd, int nameid, int seconds)
+{ // '<ItemName>' item will disappear in <seconds/60> minutes.
+ WFIFOHEAD(fd,8);
+ WFIFOW(fd,0) = 0x0298;
+ WFIFOW(fd,2) = nameid;
+ WFIFOL(fd,4) = seconds;
+ WFIFOSET(fd,8);
+}
+
+void clif_rental_expired(int fd, int nameid)
+{ // '<ItemName>' item has been deleted from the Inventory
+ WFIFOHEAD(fd,6);
+ WFIFOW(fd,0) = 0x0299;
+ WFIFOW(fd,2) = 0;
+ WFIFOW(fd,4) = nameid;
+ WFIFOSET(fd,6);
+}
+
/*==========================================
* パケットデバッグ
*------------------------------------------*/
diff --git a/src/map/clif.h b/src/map/clif.h
index 5c28d65a2..1f79445ee 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -445,4 +445,8 @@ void clif_mercenary_skillblock(struct map_session_data *sd);
void clif_mercenary_message(int fd, int message);
void clif_mercenary_updatestatus(struct map_session_data *sd, int type);
+// RENTAL SYSTEM
+void clif_rental_time(int fd, int nameid, int seconds);
+void clif_rental_expired(int fd, int nameid);
+
#endif /* _CLIF_H_ */
diff --git a/src/map/mail.c b/src/map/mail.c
index d77dbe6b4..072368838 100644
--- a/src/map/mail.c
+++ b/src/map/mail.c
@@ -69,16 +69,14 @@ int mail_removezeny(struct map_session_data *sd, short flag)
unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount)
{
- if (idx == 0)
+ if( idx == 0 )
{ // Zeny Transfer
- if( amount < 0 )
- return 0;
+ if( amount < 0 || !pc_can_give_items(pc_isGM(sd)) )
+ return 1;
+
if( amount > sd->status.zeny )
amount = sd->status.zeny;
- if( !pc_can_give_items(pc_isGM(sd)) )
- amount = 0;
-
sd->mail.zeny = amount;
// clif_updatestatus(sd, SP_ZENY);
return 0;
@@ -94,6 +92,8 @@ unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount)
return 1;
if( !pc_candrop(sd, &sd->status.inventory[idx]) )
return 1;
+ if( sd->status.inventory[idx].expire_time )
+ return 1; // Rental System
sd->mail.index = idx;
sd->mail.nameid = sd->status.inventory[idx].nameid;
@@ -174,7 +174,7 @@ void mail_deliveryfail(struct map_session_data *sd, struct mail_message *msg)
nullpo_retv(sd);
nullpo_retv(msg);
- // Item recieve (due to failure)
+ // Item recieve (due to failure)
if(log_config.enable_logs&0x2000)
log_pick_pc(sd, "E", msg->item.nameid, msg->item.amount, &msg->item);
diff --git a/src/map/pc.c b/src/map/pc.c
index 62a875e13..4efdff069 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -281,6 +281,88 @@ int pc_setrestartvalue(struct map_session_data *sd,int type)
}
/*==========================================
+ Rental System
+ *------------------------------------------*/
+static int pc_inventory_rental_end(int tid, unsigned int tick, int id, intptr data)
+{
+ struct map_session_data *sd = map_id2sd(id);
+ if( sd == NULL )
+ return 0;
+ if( tid != sd->rental_timer )
+ {
+ ShowError("pc_inventory_rental_end: invalid timer id.\n");
+ return 0;
+ }
+
+ pc_inventory_rentals(sd);
+ return 1;
+}
+
+int pc_inventory_rental_clear(struct map_session_data *sd)
+{
+ if( sd->rental_timer != INVALID_TIMER )
+ {
+ delete_timer(sd->rental_timer, pc_inventory_rental_end);
+ sd->rental_timer = -1;
+ }
+
+ return 1;
+}
+
+void pc_inventory_rentals(struct map_session_data *sd)
+{
+ int i, c = 0;
+ unsigned int expire_tick, next_tick = UINT_MAX;
+
+ for( i = 0; i < MAX_INVENTORY; i++ )
+ {
+ if( sd->status.inventory[i].nameid == 0 )
+ continue; // Nothing here
+ if( sd->status.inventory[i].expire_time == 0 )
+ continue;
+
+ if( sd->status.inventory[i].expire_time <= time(NULL) )
+ {
+ clif_rental_expired(sd->fd, sd->status.inventory[i].nameid);
+ pc_delitem(sd, i, sd->status.inventory[i].amount, 0);
+ }
+ else
+ {
+ expire_tick = (unsigned int)(sd->status.inventory[i].expire_time - time(NULL)) * 1000;
+ clif_rental_time(sd->fd, sd->status.inventory[i].nameid, (int)(expire_tick / 1000));
+ next_tick = min(expire_tick, next_tick);
+ c++;
+ }
+ }
+
+ if( c > 0 )
+ sd->rental_timer = add_timer(gettick() + next_tick, pc_inventory_rental_end, sd->bl.id, 0);
+ else
+ sd->rental_timer = -1;
+}
+
+void pc_inventory_rental_add(struct map_session_data *sd, int seconds)
+{
+ const struct TimerData * td;
+ int tick = seconds * 1000;
+
+ if( sd == NULL )
+ return;
+
+ if( sd->rental_timer != INVALID_TIMER )
+ {
+ td = get_timer(sd->rental_timer);
+ if( DIFF_TICK(td->tick, gettick()) > tick )
+ { // Update Timer as this one ends first than the current one
+ pc_inventory_rental_clear(sd);
+ sd->rental_timer = add_timer(gettick() + tick, pc_inventory_rental_end, sd->bl.id, 0);
+ }
+ }
+ else
+ sd->rental_timer = add_timer(gettick() + tick, pc_inventory_rental_end, sd->bl.id, 0);
+}
+
+/*==========================================
Determines if the GM can give / drop / trade / vend items
Args: GM Level (current player GM level)
*------------------------------------------*/
@@ -732,7 +814,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
// アイテムチェック
pc_setinventorydata(sd);
pc_checkitem(sd);
-
+
status_change_init(&sd->bl);
if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) && (pc_isGM(sd) >= get_atcommand_level(atcommand_hide)))
sd->status.option &= (OPTION_MASK | OPTION_INVISIBLE);
@@ -747,11 +829,13 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
sd->guild_x = -1;
sd->guild_y = -1;
- // イベント?係の初期化
- for(i = 0; i < MAX_EVENTTIMER; i++)
+ // Event Timers
+ for( i = 0; i < MAX_EVENTTIMER; i++ )
sd->eventtimer[i] = -1;
+ // Rental Timer
+ sd->rental_timer = -1;
- for (i = 0; i < 3; i++)
+ for( i = 0; i < 3; i++ )
sd->hate_mob[i] = -1;
// 位置の設定
@@ -873,7 +957,7 @@ int pc_reg_received(struct map_session_data *sd)
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
+ { // Better check for class rather than skill to prevent "skill resets" from unsetting this
sd->mission_mobid = pc_readglobalreg(sd,"TK_MISSION_ID");
sd->mission_count = pc_readglobalreg(sd,"TK_MISSION_COUNT");
}
@@ -940,6 +1024,10 @@ int pc_reg_received(struct map_session_data *sd)
sd->state.connect_new = 1;
clif_parse_LoadEndAck(sd->fd, sd);
}
+
+#ifndef TXT_ONLY
+ pc_inventory_rentals(sd);
+#endif
return 1;
}
@@ -2982,12 +3070,14 @@ int pc_dropitem(struct map_session_data *sd,int n,int amount)
)
return 0;
- if (map[sd->bl.m].flag.nodrop) {
+ if( map[sd->bl.m].flag.nodrop )
+ {
clif_displaymessage (sd->fd, msg_txt(271));
return 0; //Can't drop items in nodrop mapflag maps.
}
- if (!pc_candrop(sd,&sd->status.inventory[n])) {
+ if( !pc_candrop(sd,&sd->status.inventory[n]) || sd->status.inventory[n].expire_time )
+ {
clif_displaymessage (sd->fd, msg_txt(263));
return 0;
}
@@ -3291,17 +3381,17 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun
return 1;
data = itemdb_search(item_data->nameid);
- if(!itemdb_cancartstore(item_data, pc_isGM(sd)))
- { //Check item trade restrictions [Skotlex]
+ if( item_data->expire_time || !itemdb_cancartstore(item_data, pc_isGM(sd)) )
+ { // Check item trade restrictions [Skotlex]
clif_displaymessage (sd->fd, msg_txt(264));
return 1;
}
- if((w=data->weight*amount) + sd->cart_weight > battle_config.max_cart_weight)
+ if( (w = data->weight*amount) + sd->cart_weight > battle_config.max_cart_weight )
return 1;
- i=MAX_CART;
- if(itemdb_isstackable2(data))
+ i = MAX_CART;
+ if( itemdb_isstackable2(data) )
{
ARR_FIND( 0, MAX_CART, i,
sd->status.cart[i].nameid == item_data->nameid &&
@@ -7562,6 +7652,7 @@ int do_init_pc(void)
add_timer_func_list(pc_invincible_timer, "pc_invincible_timer");
add_timer_func_list(pc_eventtimer, "pc_eventtimer");
+ add_timer_func_list(pc_inventory_rental_end, "pc_inventory_rental_end");
add_timer_func_list(pc_calc_pvprank_timer, "pc_calc_pvprank_timer");
add_timer_func_list(pc_autosave, "pc_autosave");
add_timer_func_list(pc_spiritball_timer, "pc_spiritball_timer");
diff --git a/src/map/pc.h b/src/map/pc.h
index 16ee1936b..aae1e6550 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -340,6 +340,7 @@ struct map_session_data {
char away_message[128]; // [LuzZza]
int cashPoints, kafraPoints;
+ int rental_timer;
// Auction System [Zephyrus]
struct {
@@ -711,6 +712,11 @@ extern int night_timer_tid;
int map_day_timer(int tid, unsigned int tick, int id, intptr data); // by [yor]
int map_night_timer(int tid, unsigned int tick, int id, intptr data); // by [yor]
+// Rental System
+void pc_inventory_rentals(struct map_session_data *sd);
+int pc_inventory_rental_clear(struct map_session_data *sd);
+void pc_inventory_rental_add(struct map_session_data *sd, int seconds);
+
//Duel functions // [LuzZza]
int duel_create(struct map_session_data* sd, const unsigned int maxpl);
int duel_invite(const unsigned int did, struct map_session_data* sd, struct map_session_data* target_sd);
diff --git a/src/map/script.c b/src/map/script.c
index 1736b7f05..f56d388c3 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -5239,6 +5239,77 @@ BUILDIN_FUNC(getitem2)
}
/*==========================================
+ * rentitem <item id>
+ * rentitem "<item name>"
+ *------------------------------------------*/
+BUILDIN_FUNC(rentitem)
+{
+ struct map_session_data *sd;
+ struct script_data *data;
+ struct item it;
+ int seconds;
+ int nameid = 0, flag;
+
+ data = script_getdata(st,2);
+ get_val(st,data);
+
+ if( (sd = script_rid2sd(st)) == NULL )
+ return 0;
+
+ if( data_isstring(data) )
+ {
+ const char *name = conv_str(st,data);
+ struct item_data *itd = itemdb_searchname(name);
+ if( itd == NULL )
+ {
+ ShowError("buildin_rentitem: Nonexistant item %s requested.\n", name);
+ return 1;
+ }
+ nameid = itd->nameid;
+ }
+ else if( data_isint(data) )
+ {
+ nameid = conv_num(st,data);
+ if( nameid <= 0 || !itemdb_exists(nameid) )
+ {
+ ShowError("buildin_rentitem: Nonexistant item %d requested.\n", nameid);
+ return 1;
+ }
+ }
+ else
+ {
+ ShowError("buildin_rentitem: invalid data type for argument #1 (%d).\n", data->type);
+ return 1;
+ }
+
+ if( itemdb_isstackable(nameid) )
+ {
+ ShowError("buildin_rentitem: invalid rental item %d requested.\n", nameid);
+ return 1;
+ }
+
+ seconds = script_getnum(st,3);
+ memset(&it, 0, sizeof(it));
+ it.nameid = nameid;
+ it.identify = 1;
+ it.expire_time = (unsigned int)(time(NULL) + seconds);
+
+ if( (flag = pc_additem(sd, &it, 1)) )
+ {
+ clif_additem(sd, 0, 0, flag);
+ return 1;
+ }
+
+ clif_rental_time(sd->fd, nameid, seconds);
+ pc_inventory_rental_add(sd, seconds);
+
+ if( log_config.enable_logs&LOG_SCRIPT_TRANSACTIONS )
+ log_pick_pc(sd, "N", nameid, 1, NULL);
+
+ return 0;
+}
+
+/*==========================================
* gets an item with someone's name inscribed [Skotlex]
* getinscribeditem item_num, character_name
* Returned Qty is always 1, only works on equip-able
@@ -9580,8 +9651,8 @@ BUILDIN_FUNC(mapwarp) // Added by RoVeRT
static int buildin_mobcount_sub(struct block_list *bl,va_list ap) // Added by RoVeRT
{
char *event=va_arg(ap,char *);
- struct mob_data *md = ((struct mob_data *)bl);
- if(strcmp(event,md->npc_event)==0 && md->status.hp > 0)
+ struct mob_data *md = ((struct mob_data *)bl);
+ if(strcmp(event,md->npc_event)==0 && md->status.hp > 0)
return 1;
return 0;
}
@@ -13186,6 +13257,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(deletearray,"r?"),
BUILDIN_DEF(getelementofarray,"ri"),
BUILDIN_DEF(getitem,"vi?"),
+ BUILDIN_DEF(rentitem,"vi"),
BUILDIN_DEF(getitem2,"iiiiiiiii*"),
BUILDIN_DEF(getnameditem,"is"),
BUILDIN_DEF2(grouprandomitem,"groupranditem","i"),
diff --git a/src/map/storage.c b/src/map/storage.c
index e4bdfe414..33a72d0d7 100644
--- a/src/map/storage.c
+++ b/src/map/storage.c
@@ -112,10 +112,11 @@ int storage_storageopen(struct map_session_data *sd)
// helper function
int compare_item(struct item *a, struct item *b)
{
- if (a->nameid == b->nameid &&
+ if( a->nameid == b->nameid &&
a->identify == b->identify &&
a->refine == b->refine &&
- a->attribute == b->attribute)
+ a->attribute == b->attribute &&
+ a->expire_time == b->expire_time )
{
int i;
for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++);
@@ -215,7 +216,10 @@ int storage_storageadd(struct map_session_data* sd, int index, int amount)
return 0;
if( sd->status.inventory[index].nameid <= 0 )
- return 0; //No item on that spot
+ return 0; // No item on that spot
+
+ if( sd->status.inventory[index].expire_time )
+ return 0; // Cannot Store Rental Items
if( amount < 1 || amount > sd->status.inventory[index].amount )
return 0;
@@ -266,6 +270,9 @@ int storage_storageaddfromcart(struct map_session_data* sd, int index, int amoun
if( sd->status.cart[index].nameid <= 0 )
return 0; //No item there.
+ if( sd->status.inventory[index].expire_time )
+ return 0; // Cannot Store Rental Items
+
if( amount < 1 || amount > sd->status.cart[index].amount )
return 0;
@@ -462,16 +469,19 @@ int storage_guild_storageadd(struct map_session_data* sd, int index, int amount)
nullpo_retr(0, sd);
nullpo_retr(0, stor=guild2storage2(sd->status.guild_id));
- if (!stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE)
+ if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE )
return 0;
- if(index<0 || index>=MAX_INVENTORY)
+ if( index<0 || index>=MAX_INVENTORY )
return 0;
- if(sd->status.inventory[index].nameid <= 0)
+ if( sd->status.inventory[index].nameid <= 0 )
return 0;
- if(amount < 1 || amount > sd->status.inventory[index].amount)
+ if( amount < 1 || amount > sd->status.inventory[index].amount )
+ return 0;
+
+ if( sd->status.inventory[index].expire_time )
return 0;
// log_tostorage(sd, index, 1);
@@ -517,16 +527,19 @@ int storage_guild_storageaddfromcart(struct map_session_data* sd, int index, int
nullpo_retr(0, sd);
nullpo_retr(0, stor=guild2storage2(sd->status.guild_id));
- if(!stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE)
+ if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE )
return 0;
- if(index<0 || index>=MAX_CART)
+ if( index < 0 || index >= MAX_CART )
return 0;
- if(sd->status.cart[index].nameid <= 0)
+ if( sd->status.cart[index].nameid <= 0 )
return 0;
- if(amount < 1 || amount > sd->status.cart[index].amount)
+ if( amount < 1 || amount > sd->status.cart[index].amount )
+ return 0;
+
+ if( sd->status.inventory[index].expire_time )
return 0;
if(guild_storage_additem(sd,stor,&sd->status.cart[index],amount)==0)
diff --git a/src/map/trade.c b/src/map/trade.c
index aca08872a..7d6a4c8b2 100644
--- a/src/map/trade.c
+++ b/src/map/trade.c
@@ -354,6 +354,13 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount)
return;
}
+ if( item->expire_time )
+ { // Rental System
+ clif_displaymessage (sd->fd, msg_txt(260));
+ clif_tradeitemok(sd, index+2, 1);
+ return;
+ }
+
//Locate a trade position
ARR_FIND( 0, 10, trade_i, sd->deal.item[trade_i].index == index || sd->deal.item[trade_i].amount == 0 );
if( trade_i == 10 ) //No space left
diff --git a/src/map/unit.c b/src/map/unit.c
index 3049f0457..7373ebab1 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -1941,6 +1941,7 @@ int unit_free(struct block_list *bl, int clrtype)
party_send_logout(sd);
guild_send_memberinfoshort(sd,0);
pc_cleareventtimer(sd);
+ pc_inventory_rental_clear(sd);
pc_delspiritball(sd,sd->spiritball,1);
if( sd->reg )