Explorar o código

- Rental items now can be stackable items too.
- Added @font command to test kRO fonts. (Client side requires : Langtype 0 / Hex + Fonts Files on the data folder).
- Rental now announces with a maximum time to fix a problem with 1 month or more rentals.
- Reduced amount of calculations of Flee on map change (only if required).
- More security on Rental items.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@13761 54d463be-8e91-2dee-dedb-b68131a5f0ec

zephyrus %!s(int64=16) %!d(string=hai) anos
pai
achega
15a8174e29
Modificáronse 8 ficheiros con 169 adicións e 74 borrados
  1. 58 22
      src/map/atcommand.c
  2. 34 2
      src/map/clif.c
  3. 4 0
      src/map/clif.h
  4. 43 34
      src/map/pc.c
  5. 2 0
      src/map/pc.h
  6. 24 12
      src/map/script.c
  7. 3 4
      src/map/skill.c
  8. 1 0
      src/map/vending.c

+ 58 - 22
src/map/atcommand.c

@@ -8586,6 +8586,42 @@ int atcommand_delitem(const int fd, struct map_session_data* sd, const char* com
 	return 0;
 }
 
+/*==========================================
+ * Custom Fonts
+ *------------------------------------------*/
+int atcommand_font(const int fd, struct map_session_data *sd, const char *command, const char *message)
+{
+	int font_id;
+	nullpo_retr(-1,sd);
+
+	font_id = atoi(message);
+	if( font_id == 0 )
+	{
+		if( sd->state.user_font )
+		{
+			sd->state.user_font = 0;
+			clif_displaymessage(fd, "Returning to normal font.");
+			clif_font_area(sd);
+		}
+		else
+		{
+			clif_displaymessage(fd, "Use @font <1..9> to change your messages font.");
+			clif_displaymessage(fd, "Use 0 or no parameter to back to normal font.");
+		}
+	}
+	else if( font_id < 0 || font_id > 9 )
+		clif_displaymessage(fd, "Invalid font. Use a Value from 0 to 9.");
+	else if( font_id != sd->state.user_font )
+	{
+		sd->state.user_font = font_id;
+		clif_font_area(sd);
+		clif_displaymessage(fd, "Font changed.");
+	}
+	else
+		clif_displaymessage(fd, "Already using this font.");
+
+	return 0;
+}
 
 
 /*==========================================
@@ -8890,6 +8926,7 @@ AtCommandInfo atcommand_info[] = {
 	{ "stats",              40,40,    atcommand_stats },
 	{ "delitem",            60,60,    atcommand_delitem },
 	{ "charcommands",        1,1,     atcommand_commands },
+	{ "font",               1,1,     atcommand_font },
 };
 
 
@@ -9147,36 +9184,35 @@ int atcommand_commands(const int fd, struct map_session_data* sd, const char* co
 
 	clif_displaymessage(fd, msg_txt(273)); // "Commands available:"
 
-		for( i = 0; i < ARRAYLENGTH(atcommand_info); i++ )
-		{
-			unsigned int slen;
+	for( i = 0; i < ARRAYLENGTH(atcommand_info); i++ )
+	{
+		unsigned int slen;
 
-			if( gm_lvl < atcommand_info[i].level && stristr(command,"commands") )
-				continue;
-			if( gm_lvl < atcommand_info[i].level2 && stristr(command,"charcommands") )
-				continue;
+		if( gm_lvl < atcommand_info[i].level && stristr(command,"commands") )
+			continue;
+		if( gm_lvl < atcommand_info[i].level2 && stristr(command,"charcommands") )
+			continue;
 
-			slen = (unsigned int)strlen(atcommand_info[i].command);
+		slen = (unsigned int)strlen(atcommand_info[i].command);
 
-			// flush the text buffer if this command won't fit into it
-			if( slen + cur - line_buff >= CHATBOX_SIZE )
-			{
-				clif_displaymessage(fd,line_buff);
-				cur = line_buff;
-				memset(line_buff,' ',CHATBOX_SIZE);
-				line_buff[CHATBOX_SIZE-1] = 0;
-			}
+		// flush the text buffer if this command won't fit into it
+		if( slen + cur - line_buff >= CHATBOX_SIZE )
+		{
+			clif_displaymessage(fd,line_buff);
+			cur = line_buff;
+			memset(line_buff,' ',CHATBOX_SIZE);
+			line_buff[CHATBOX_SIZE-1] = 0;
+		}
 
-			memcpy(cur,atcommand_info[i].command,slen);
-			cur += slen+(10-slen%10);
+		memcpy(cur,atcommand_info[i].command,slen);
+		cur += slen+(10-slen%10);
 
-			count++;
-		}
-		
+		count++;
+	}
 	clif_displaymessage(fd,line_buff);
 
 	sprintf(atcmd_output, msg_txt(274), count); // "%d commands found."
 	clif_displaymessage(fd, atcmd_output);
-	
+
 	return 0;
 }

+ 34 - 2
src/map/clif.c

@@ -1062,6 +1062,8 @@ int clif_spawn(struct block_list *bl)
 				clif_specialeffect(bl,423,AREA);
 			else if(sd->state.size==1)
 				clif_specialeffect(bl,421,AREA);
+			if( sd->state.user_font )
+				clif_font_area(sd);
 			if( sd->state.bg_id && map[sd->bl.m].flag.battleground )
 				clif_sendbgemblem_area(sd);
 		}
@@ -3486,6 +3488,8 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl)
 				clif_specialeffect_single(bl,423,sd->fd);
 			else if(tsd->state.size==1)
 				clif_specialeffect_single(bl,421,sd->fd);
+			if( tsd->state.user_font )
+				clif_font_single(sd->fd,tsd);
 			if( tsd->state.bg_id && map[tsd->bl.m].flag.battleground )
 				clif_sendbgemblem_single(sd->fd,tsd);
 		}
@@ -8125,8 +8129,10 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
 
 	if( sd->state.changemap )
 	{// restore information that gets lost on map-change
-		if( battle_config.gvg_flee_penalty != 100 || battle_config.bg_flee_penalty != 100 )
+		if( (map_flag_gvg(sd->state.pmap) && battle_config.gvg_flee_penalty != 100) || (map[sd->state.pmap].flag.battleground && battle_config.bg_flee_penalty != 100) )
 			status_calc_bl(&sd->bl, SCB_FLEE); //Refresh flee penalty
+		else if( (map_flag_gvg(sd->bl.m) && battle_config.gvg_flee_penalty != 100) || (map[sd->bl.m].flag.battleground && battle_config.bg_flee_penalty != 100) )
+			status_calc_bl(&sd->bl, SCB_FLEE);
 
 		if( night_flag && map[sd->bl.m].flag.nightenabled )
 		{	//Display night.
@@ -13012,6 +13018,32 @@ int clif_sendbgemblem_single(int fd, struct map_session_data *sd)
 	return 0;
 }
 
+/*==========================================
+ * Custom Fonts
+ * S 0x2ef <account_id>.l <font id>.w
+ *------------------------------------------*/
+int clif_font_area(struct map_session_data *sd)
+{
+	unsigned char buf[8];
+	nullpo_retr(0,sd);
+	WBUFW(buf,0) = 0x2ef;
+	WBUFL(buf,2) = sd->bl.id;
+	WBUFW(buf,6) = sd->state.user_font;
+	clif_send(buf, packet_len(0x2ef), &sd->bl, AREA);
+	return 1;
+}
+
+int clif_font_single(int fd, struct map_session_data *sd)
+{
+	nullpo_retr(0,sd);
+	WFIFOHEAD(fd,packet_len(0x2ef));
+	WFIFOW(fd,0) = 0x2ef;
+	WFIFOL(fd,2) = sd->bl.id;
+	WFIFOW(fd,6) = sd->state.user_font;
+	WFIFOSET(fd,packet_len(0x2ef));
+	return 1;
+}
+
 /*==========================================
  * ƒpƒPƒbƒgƒfƒoƒbƒO
  *------------------------------------------*/
@@ -13286,7 +13318,7 @@ static int packetdb_readdb(void)
 	//#0x02C0
 	    0,  0,  0,  0,  0, 30,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	    0,  0,  0,  0,  0,  0,  6, -1, 10, 10,  0,  0, -1, 32,  6,  0,
-	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8,
 	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	//#0x0300
 	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,

+ 4 - 0
src/map/clif.h

@@ -350,6 +350,10 @@ int clif_bg_updatescore_single(struct map_session_data *sd);
 int clif_sendbgemblem_area(struct map_session_data *sd);
 int clif_sendbgemblem_single(int fd, struct map_session_data *sd);
 
+// Custom Fonts
+int clif_font_area(struct map_session_data *sd);
+int clif_font_single(int fd, struct map_session_data *sd);
+
 // atcommand
 int clif_displaymessage(const int fd,const char* mes);
 int clif_disp_onlyself(struct map_session_data *sd,const char *mes,int len);

+ 43 - 34
src/map/pc.c

@@ -349,10 +349,10 @@ void pc_inventory_rentals(struct map_session_data *sd)
 		}
 	}
 
-	if( c > 0 )
-		sd->rental_timer = add_timer(gettick() + next_tick, pc_inventory_rental_end, sd->bl.id, 0);
+	if( c > 0 ) // min(next_tick,3600000) 1 hour each timer to keep announcing to the owner, and to avoid a but with rental time > 15 days
+		sd->rental_timer = add_timer(gettick() + min(next_tick,3600000), pc_inventory_rental_end, sd->bl.id, 0);
 	else
-		sd->rental_timer = -1;
+		sd->rental_timer = INVALID_TIMER;
 }
 
 void pc_inventory_rental_add(struct map_session_data *sd, int seconds)
@@ -848,7 +848,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
 	for( i = 0; i < MAX_EVENTTIMER; i++ )
 		sd->eventtimer[i] = -1;
 	// Rental Timer
-	sd->rental_timer = -1;
+	sd->rental_timer = INVALID_TIMER;
 
 	for( i = 0; i < 3; i++ )
 		sd->hate_mob[i] = -1;
@@ -3119,9 +3119,9 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount)
 	nullpo_retr(1, sd);
 	nullpo_retr(1, item_data);
 
-	if(item_data->nameid <= 0 || amount <= 0)
+	if( item_data->nameid <= 0 || amount <= 0 )
 		return 1;
-	if(amount > MAX_AMOUNT)
+	if( amount > MAX_AMOUNT )
 		return 5;
 	
 	data = itemdb_search(item_data->nameid);
@@ -3131,15 +3131,13 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount)
 
 	i = MAX_INVENTORY;
 
-	if (itemdb_isstackable2(data))
-	{ //Stackable
-		for (i = 0; i < MAX_INVENTORY; i++)
+	if( itemdb_isstackable2(data) && item_data->serial == 0 && item_data->expire_time == 0 )
+	{ // Stackable | Non Serialized (non unique) | Non Rental
+		for( i = 0; i < MAX_INVENTORY; i++ )
 		{
-			if(sd->status.inventory[i].nameid == item_data->nameid &&
-				memcmp(&sd->status.inventory[i].card,&item_data->card,
-					sizeof(item_data->card))==0)
+			if( sd->status.inventory[i].nameid == item_data->nameid && memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 )
 			{
-				if (amount > MAX_AMOUNT - sd->status.inventory[i].amount)
+				if( amount > MAX_AMOUNT - sd->status.inventory[i].amount )
 					return 5;
 				sd->status.inventory[i].amount += amount;
 				clif_additem(sd,i,amount,0);
@@ -3147,12 +3145,16 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount)
 			}
 		}
 	}
-	if (i >= MAX_INVENTORY){
+
+	if( i >= MAX_INVENTORY )
+	{
 		i = pc_search_inventory(sd,0);
-		if(i<0) return 4;
+		if( i < 0 )
+			return 4;
+
 		memcpy(&sd->status.inventory[i], item_data, sizeof(sd->status.inventory[0]));
 		// clear equips field first, just in case
-		if (item_data->equip)
+		if( item_data->equip )
 			sd->status.inventory[i].equip = 0;
 
 		sd->status.inventory[i].amount = amount;
@@ -3447,18 +3449,17 @@ int pc_useitem(struct map_session_data *sd,int n)
 
 	nullpo_retr(0, sd);
 
-	if(sd->status.inventory[n].nameid <= 0 ||
-		sd->status.inventory[n].amount <= 0)
+	if( sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0 )
 		return 0;
 
-	if(!pc_isUseitem(sd,n))
+	if( !pc_isUseitem(sd,n) )
 		return 0;
 
 	 //Prevent mass item usage. [Skotlex]
-	if(DIFF_TICK(sd->canuseitem_tick, tick) > 0)
+	if( DIFF_TICK(sd->canuseitem_tick, tick) > 0 )
 		return 0;
 
-	if (sd->sc.count && (
+	if( sd->sc.count && (
 		sd->sc.data[SC_BERSERK] ||
 		(sd->sc.data[SC_GRAVITATION] && sd->sc.data[SC_GRAVITATION]->val3 == BCT_SELF) ||
 		sd->sc.data[SC_TRICKDEAD] ||
@@ -3484,15 +3485,22 @@ int pc_useitem(struct map_session_data *sd,int n)
 	amount = sd->status.inventory[n].amount;
 	script = sd->inventory_data[n]->script;
 	//Check if the item is to be consumed immediately [Skotlex]
-	if (sd->inventory_data[n]->flag.delay_consume)
+	if( sd->inventory_data[n]->flag.delay_consume )
 		clif_useitemack(sd,n,amount,1);
-	else {
-		clif_useitemack(sd,n,amount-1,1);
-		//Logs (C)onsumable items [Lupus]
-		if(log_config.enable_logs&0x100)
-			log_pick_pc(sd, "C", sd->status.inventory[n].nameid, -1, &sd->status.inventory[n]);
-		//Logs
-		pc_delitem(sd,n,1,1);
+	else
+	{
+		if( sd->status.inventory[n].expire_time == 0 )
+		{
+			clif_useitemack(sd,n,amount-1,1);
+
+			//Logs (C)onsumable items [Lupus]
+			if( log_config.enable_logs&0x100 )
+				log_pick_pc(sd, "C", sd->status.inventory[n].nameid, -1, &sd->status.inventory[n], sd->status.inventory[n].serial );
+
+			pc_delitem(sd,n,1,1); // Rental Usable Items are not deleted until expiration
+		}
+		else
+			clif_useitemack(sd,n,0,0);
 	}
 	if(sd->status.inventory[n].card[0]==CARD0_CREATE &&
 		pc_famerank(MakeDWord(sd->status.inventory[n].card[2],sd->status.inventory[n].card[3]), MAPID_ALCHEMIST))
@@ -3533,7 +3541,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun
 		return 1;
 
 	i = MAX_CART;
-	if( itemdb_isstackable2(data) )
+	if( itemdb_isstackable2(data) && !item_data->expire_time )
 	{
 		ARR_FIND( 0, MAX_CART, i,
 			sd->status.cart[i].nameid == item_data->nameid &&
@@ -3606,10 +3614,10 @@ int pc_putitemtocart(struct map_session_data *sd,int idx,int amount)
 	
 	item_data = &sd->status.inventory[idx];
 
-	if (item_data->nameid==0 || amount < 1 || item_data->amount<amount || sd->vender_id)
+	if( item_data->nameid == 0 || amount < 1 || item_data->amount < amount || sd->vender_id || item_data->expire_time )
 		return 1;
 
-	if (pc_cart_additem(sd,item_data,amount) == 0)
+	if( pc_cart_additem(sd,item_data,amount) == 0 )
 		return pc_delitem(sd,idx,amount,0);
 
 	return 1;
@@ -3814,9 +3822,10 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y
 
 	sd->state.changemap = (sd->mapindex != mapindex);
 	if( sd->state.changemap )
-	{	//Misc map-changing settings
+	{ // Misc map-changing settings
+		sd->state.pmap = sd->bl.m;
 		if (sd->sc.count)
-		{ //Cancel some map related stuff.
+		{ // Cancel some map related stuff.
 			if (sd->sc.data[SC_JAILED])
 				return 1; //You may not get out!
 			if (sd->sc.data[SC_BOSSMAPINFO])

+ 2 - 0
src/map/pc.h

@@ -120,9 +120,11 @@ struct map_session_data {
 		unsigned short autolootid; // [Zephyrus]
 		unsigned noks : 3; // [Zeph Kill Steal Protection]
 		bool changemap;
+		short pmap; // Previous map on Map Change
 		struct guild *gmaster_flag;
 		unsigned int bg_id;
 		unsigned skillonskill : 1;
+		unsigned short user_font;
 	} state;
 	struct {
 		unsigned char no_weapon_damage, no_magic_damage, no_misc_damage;

+ 24 - 12
src/map/script.c

@@ -5356,12 +5356,6 @@ BUILDIN_FUNC(rentitem)
 		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;
@@ -6268,14 +6262,12 @@ BUILDIN_FUNC(getequipisenableref)
 	if( sd == NULL )
 		return 0;
 
-	if (num > 0 && num <= ARRAYLENGTH(equip))
-		i=pc_checkequip(sd,equip[num-1]);
-	if(i >= 0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_refine)
-	{
+	if( num > 0 && num <= ARRAYLENGTH(equip) )
+		i = pc_checkequip(sd,equip[num-1]);
+	if( i >= 0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_refine && !sd->status.inventory[i].expire_time )
 		script_pushint(st,1);
-	} else {
+	else
 		script_pushint(st,0);
-	}
 
 	return 0;
 }
@@ -13640,6 +13632,25 @@ BUILDIN_FUNC(bg_get_data)
 	return 0;
 }
 
+/*==========================================
+ * Custom Fonts
+ *------------------------------------------*/
+BUILDIN_FUNC(setfont)
+{
+	struct map_session_data *sd = script_rid2sd(st);
+	int font = script_getnum(st,2);
+	if( sd == NULL )
+		return 0;
+
+	if( sd->state.user_font != font )
+		sd->state.user_font = font;
+	else
+		sd->state.user_font = 0;
+	
+	clif_font_area(sd);
+	return 0;
+}
+
 // declarations that were supposed to be exported from npc_chat.c
 #ifdef PCRE_SUPPORT
 BUILDIN_FUNC(defpattern);
@@ -13998,6 +14009,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(mercenary_set_calls,"ii"),
 	BUILDIN_DEF(mercenary_set_faith,"ii"),
 	BUILDIN_DEF(readbook,"ii"),
+	BUILDIN_DEF(setfont,"i"),
 	// WoE SE
 	BUILDIN_DEF(agitstart2,""),
 	BUILDIN_DEF(agitend2,""),

+ 3 - 4
src/map/skill.c

@@ -7995,11 +7995,10 @@ int skill_check_condition(struct map_session_data* sd, short skill, short lv, in
 			}
 			//Consume
 			sd->itemid = sd->itemindex = -1;
-			if(skill == WZ_EARTHSPIKE && sc &&
-				sc->data[SC_EARTHSCROLL] && rand()%100 > sc->data[SC_EARTHSCROLL]->val2) // [marquis007]
+			if( skill == WZ_EARTHSPIKE && sc && sc->data[SC_EARTHSCROLL] && rand()%100 > sc->data[SC_EARTHSCROLL]->val2 ) // [marquis007]
 				; //Do not consume item.
-			else
-				pc_delitem(sd,i,1,0);
+			else if( sd->status.inventory[i].expire_time == 0 )
+				pc_delitem(sd,i,1,0); // Rental usable items are not consumed until expiration
 		}
 		if (type&1) //Casting finished
 			sd->skillitem = sd->skillitemlv = 0;

+ 1 - 0
src/map/vending.c

@@ -266,6 +266,7 @@ void vending_openvending(struct map_session_data* sd, const char* message, bool
 		//NOTE: official server does not do any of the following checks!
 		||  !sd->status.cart[index].identify // unidentified item
 		||  sd->status.cart[index].attribute == 1 // broken item
+		||  sd->status.cart[index].expire_time // It should not be in the cart but just in case
 		||  !itemdb_cantrade(&sd->status.cart[index], pc_isGM(sd), pc_isGM(sd)) ) // untradeable item
 			continue;