summaryrefslogtreecommitdiff
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
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
-rw-r--r--npc/guild/payg_cas05.txt3
-rw-r--r--sql-files/main.sql4
-rw-r--r--sql-files/upgrade_svn13370_inventory.sql6
-rw-r--r--src/char_sql/char.c75
-rw-r--r--src/common/mmo.h1
-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
14 files changed, 317 insertions, 75 deletions
diff --git a/npc/guild/payg_cas05.txt b/npc/guild/payg_cas05.txt
index acf5eb2c2..b0f48616f 100644
--- a/npc/guild/payg_cas05.txt
+++ b/npc/guild/payg_cas05.txt
@@ -50,7 +50,8 @@ pay_gld,208,268,4 script Bamboo Grove Hill#f5-3::BambooGroveHill2 722,{
if (select("Return to the guild castle.:Quit.") == 1) {
if (getcharid(2) == GetCastleData("payg_cas05",1)) {
warp "payg_cas05",276,227;
- //warp "payg_cas05",243;27; end;
+ //warp "payg_cas05",243;27;
+ end;
}
}
close;
diff --git a/sql-files/main.sql b/sql-files/main.sql
index 2e2ea2cda..f62b65baf 100644
--- a/sql-files/main.sql
+++ b/sql-files/main.sql
@@ -41,6 +41,7 @@ CREATE TABLE IF NOT EXISTS `cart_inventory` (
`card1` int(11) NOT NULL default '0',
`card2` int(11) NOT NULL default '0',
`card3` int(11) NOT NULL default '0',
+ `expire_time` int(11) unsigned NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `char_id` (`char_id`)
) ENGINE=MyISAM;
@@ -309,6 +310,7 @@ CREATE TABLE IF NOT EXISTS `guild_storage` (
`card1` smallint(11) NOT NULL default '0',
`card2` smallint(11) NOT NULL default '0',
`card3` smallint(11) NOT NULL default '0',
+ `expire_time` int(11) unsigned NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `guild_id` (`guild_id`)
) ENGINE=MyISAM;
@@ -369,6 +371,7 @@ CREATE TABLE IF NOT EXISTS `inventory` (
`card1` smallint(11) NOT NULL default '0',
`card2` smallint(11) NOT NULL default '0',
`card3` smallint(11) NOT NULL default '0',
+ `expire_time` int(11) unsigned NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `char_id` (`char_id`)
) ENGINE=MyISAM;
@@ -634,6 +637,7 @@ CREATE TABLE IF NOT EXISTS `storage` (
`card1` smallint(11) NOT NULL default '0',
`card2` smallint(11) NOT NULL default '0',
`card3` smallint(11) NOT NULL default '0',
+ `expire_time` int(11) unsigned NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `account_id` (`account_id`)
) ENGINE=MyISAM;
diff --git a/sql-files/upgrade_svn13370_inventory.sql b/sql-files/upgrade_svn13370_inventory.sql
new file mode 100644
index 000000000..dc4d5ff8a
--- /dev/null
+++ b/sql-files/upgrade_svn13370_inventory.sql
@@ -0,0 +1,6 @@
+-- Creates expire_time column on Inventory
+
+ALTER TABLE `inventory` ADD COLUMN `expire_time` INT(11) UNSIGNED NOT NULL DEFAULT '0';
+ALTER TABLE `cart_inventory` ADD COLUMN `expire_time` INT(11) UNSIGNED NOT NULL DEFAULT '0';
+ALTER TABLE `storage` ADD COLUMN `expire_time` INT(11) UNSIGNED NOT NULL DEFAULT '0';
+ALTER TABLE `guild_storage` ADD COLUMN `expire_time` INT(11) UNSIGNED NOT NULL DEFAULT '0';
diff --git a/src/char_sql/char.c b/src/char_sql/char.c
index 16392eef5..edfc19498 100644
--- a/src/char_sql/char.c
+++ b/src/char_sql/char.c
@@ -529,6 +529,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
(p->sword_calls != cp->sword_calls) || (p->sword_faith != cp->sword_faith) )
{
mercenary_owner_tosql(char_id, p);
+ strcat(save_status, " mercenary");
}
//memo points
@@ -697,7 +698,7 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
// it significantly reduces cpu load on the database server.
StringBuf_Init(&buf);
- StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`");
+ StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`");
for( j = 0; j < MAX_SLOTS; ++j )
StringBuf_Printf(&buf, ", `card%d`", j);
StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id);
@@ -712,15 +713,16 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
return 1;
}
- SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL);
- SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL);
- SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL);
- SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL);
- SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL);
- SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL);
- SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL);
+ SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL);
+ SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL);
+ SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL);
+ SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL);
+ SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL);
+ SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL);
+ SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL);
+ SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL);
for( j = 0; j < MAX_SLOTS; ++j )
- SqlStmt_BindColumn(stmt, 7+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
+ SqlStmt_BindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
// bit array indicating which inventory items have already been matched
flag = (bool*) aCallocA(max, sizeof(bool));
@@ -746,14 +748,15 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
items[i].equip == item.equip &&
items[i].identify == item.identify &&
items[i].refine == item.refine &&
- items[i].attribute == item.attribute )
+ items[i].attribute == item.attribute &&
+ items[i].expire_time == item.expire_time )
; //Do nothing.
else
{
// update all fields.
StringBuf_Clear(&buf);
- StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d'",
- tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute);
+ StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'",
+ tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time);
for( j = 0; j < MAX_SLOTS; ++j )
StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]);
StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
@@ -775,7 +778,7 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
SqlStmt_Free(stmt);
StringBuf_Clear(&buf);
- StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`", tablename, selectoption);
+ StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`", tablename, selectoption);
for( j = 0; j < MAX_SLOTS; ++j )
StringBuf_Printf(&buf, ", `card%d`", j);
StringBuf_AppendStr(&buf, ") VALUES ");
@@ -793,8 +796,8 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
else
found = true;
- StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d'",
- id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute);
+ StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u'",
+ id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time);
for( j = 0; j < MAX_SLOTS; ++j )
StringBuf_Printf(&buf, ", '%d'", items[i].card[j]);
StringBuf_AppendStr(&buf, ")");
@@ -1017,7 +1020,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
//read inventory
//`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`)
StringBuf_Init(&buf);
- StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`");
+ StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`");
for( i = 0; i < MAX_SLOTS; ++i )
StringBuf_Printf(&buf, ", `card%d`", i);
StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY);
@@ -1025,26 +1028,28 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
|| SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
|| SQL_ERROR == SqlStmt_Execute(stmt)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) )
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) )
SqlStmt_ShowDebug(stmt);
for( i = 0; i < MAX_SLOTS; ++i )
- if( SQL_ERROR == SqlStmt_BindColumn(stmt, 7+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
+ if( SQL_ERROR == SqlStmt_BindColumn(stmt, 8+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
SqlStmt_ShowDebug(stmt);
for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item));
+
strcat(t_msg, " inventory");
//read cart
//`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`)
StringBuf_Clear(&buf);
- StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`");
+ StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`");
for( j = 0; j < MAX_SLOTS; ++j )
StringBuf_Printf(&buf, ", `card%d`", j);
StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART);
@@ -1052,16 +1057,17 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
|| SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
|| SQL_ERROR == SqlStmt_Execute(stmt)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL)
- || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) )
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL)
+ || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) )
SqlStmt_ShowDebug(stmt);
for( i = 0; i < MAX_SLOTS; ++i )
- if( SQL_ERROR == SqlStmt_BindColumn(stmt, 7+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
+ if( SQL_ERROR == SqlStmt_BindColumn(stmt, 8+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
SqlStmt_ShowDebug(stmt);
for( i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
@@ -1125,11 +1131,12 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
ShowWarning("mmo_char_fromsql: ignoring invalid hotkey (hotkey=%d,type=%u,id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", hotkey_num, tmp_hotkey.type, tmp_hotkey.id, tmp_hotkey.lv, p->name, p->account_id, p->char_id);
}
strcat(t_msg, " hotkeys");
+#endif
/* Mercenary Owner DataBase */
mercenary_owner_fromsql(char_id, p);
+ strcat(t_msg, " mercenary");
-#endif
if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly!
SqlStmt_Free(stmt);
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 94c72690f..3ba9d7264 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -155,6 +155,7 @@ struct item {
char refine;
char attribute;
short card[MAX_SLOTS];
+ unsigned int expire_time;
};
struct point {
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 )