Преглед изворни кода

Added script command progressbar_npc (#2272)

* Fixes #1473
Thanks to @Tokeiburu and @kukuasir1
Lemongrass3110 пре 7 година
родитељ
комит
cf0cfe84a7
7 измењених фајлова са 118 додато и 4 уклоњено
  1. 14 1
      doc/script_commands.txt
  2. 32 2
      src/map/clif.c
  3. 2 0
      src/map/clif.h
  4. 5 0
      src/map/clif_packetdb.h
  5. 1 0
      src/map/npc.c
  6. 5 0
      src/map/npc.h
  7. 59 1
      src/map/script.c

+ 14 - 1
doc/script_commands.txt

@@ -6392,9 +6392,22 @@ This command works almost like sleep2, but displays a progress bar
 above the head of the currently attached character (like cast bar).
 Once the given amount of seconds passes, the script resumes. If the
 character moves while the progress bar progresses, it is aborted and
-the script ends. The color format is in RGB (0xRRGGBB). The color is
+the script ends. The color format is in RGB (RRGGBB). The color is
 currently ignored by the client and appears always green.
 
+---------------------------------------
+
+*progressbar_npc "<color>",<seconds>{,<"NPC Name">};
+
+This command works like progressbar, but displays a progress bar
+above the head of the currently attached (or given) NPC. Once the
+given amount of seconds passes, the script resumes. The color format
+is in RGB (RRGGBB). The color is currently ignored by the client and
+appears always green.
+
+Note: If a player is attached to the NPC, they are detached from the NPC
+as soon as the progress bar activates.
+
 ---------------------------------------
 //
 5,1.- End of time-related commands

+ 32 - 2
src/map/clif.c

@@ -1466,6 +1466,7 @@ int clif_spawn(struct block_list *bl)
 			else if( nd->size == SZ_MEDIUM )
 				clif_specialeffect(&nd->bl,421,AREA);
 			clif_efst_status_change_sub(bl, bl, AREA);
+			clif_progressbar_npc_area(nd);
 		}
 		break;
 	case BL_PET:
@@ -4640,6 +4641,7 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl)
 			else if( nd->size == SZ_MEDIUM )
 				clif_specialeffect_single(bl,421,sd->fd);
 			clif_efst_status_change_sub(&sd->bl, bl, SELF);
+			clif_progressbar_npc(nd, sd);
 		}
 		break;
 	case BL_MOB:
@@ -10628,6 +10630,26 @@ void clif_parse_progressbar(int fd, struct map_session_data * sd)
 	npc_scriptcont(sd, npc_id, false);
 }
 
+/// Displays cast-like progress bar on a NPC
+/// 09d1 <id>.L <color>.L <time>.L (ZC_PROGRESS_ACTOR)
+void clif_progressbar_npc( struct npc_data *nd, struct map_session_data* sd ){
+#if PACKETVER >= 20130821
+	unsigned char buf[14];
+
+	if( nd->progressbar.timeout > 0 ){
+		WBUFW(buf,0) = 0x9d1;
+		WBUFL(buf,2) = nd->bl.id;
+		WBUFL(buf,6) = nd->progressbar.color;
+		WBUFL(buf,10) = ( nd->progressbar.timeout - gettick() ) / 1000;
+
+		if( sd ){
+			clif_send(buf, packet_len(0x9d1), &sd->bl, SELF);
+		}else{
+			clif_send(buf, packet_len(0x9d1), &nd->bl, AREA);
+		}
+	}
+#endif
+}
 
 /// Request to walk to a certain position on the current map.
 /// 0085 <dest>.3B (CZ_REQUEST_MOVE)
@@ -11419,8 +11441,16 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd)
 				break;
 			}
 #endif
-			if( bl->m != -1 )// the user can't click floating npcs directly (hack attempt)
-				npc_click(sd,(TBL_NPC*)bl);
+			if( bl->m != -1 ){ // the user can't click floating npcs directly (hack attempt)
+				struct npc_data* nd = (struct npc_data*)bl;
+
+				// Progressbar is running
+				if( nd->progressbar.timeout > 0 ){
+					return;
+				}
+
+				npc_click(sd,nd);
+			}
 			break;
 	}
 }

+ 2 - 0
src/map/clif.h

@@ -927,6 +927,8 @@ void clif_party_show_picker(struct map_session_data * sd, struct item * item_dat
 // Progress Bar [Inkfish]
 void clif_progressbar(struct map_session_data * sd, unsigned long color, unsigned int second);
 void clif_progressbar_abort(struct map_session_data * sd);
+void clif_progressbar_npc(struct npc_data *nd, struct map_session_data* sd);
+#define clif_progressbar_npc_area(nd) clif_progressbar_npc((nd),NULL)
 
 void clif_PartyBookingRegisterAck(struct map_session_data *sd, int flag);
 void clif_PartyBookingDeleteAck(struct map_session_data* sd, int flag);

+ 5 - 0
src/map/clif_packetdb.h

@@ -2145,6 +2145,11 @@
 	parseable_packet(0x0974,2,clif_parse_merge_item_cancel,0); // CZ_CANCEL_MERGE_ITEM
 #endif
 
+// 2013-08-21bRagexe
+#if PACKETVER >= 20130821
+	packet(0x09D1,14);
+#endif
+
 // 2013-12-23Ragexe
 #if PACKETVER >= 20131223
 	//New Packets

+ 1 - 0
src/map/npc.c

@@ -2418,6 +2418,7 @@ struct npc_data *npc_create_npc(int16 m, int16 x, int16 y){
 	nd->bl.y = y;
 	nd->sc_display = NULL;
 	nd->sc_display_count = 0;
+	nd->progressbar.timeout = 0;
 
 	return nd;
 }

+ 5 - 0
src/map/npc.h

@@ -99,6 +99,11 @@ struct npc_data {
 
 	struct sc_display_entry **sc_display;
 	unsigned char sc_display_count;
+
+	struct {
+		unsigned int timeout;
+		unsigned long color;
+	} progressbar;
 };
 
 struct eri *npc_sc_display_ers;

+ 59 - 1
src/map/script.c

@@ -20264,7 +20264,10 @@ BUILDIN_FUNC(areamobuseskill)
 	return SCRIPT_CMD_SUCCESS;
 }
 
-
+/**
+ * Display a progress bar above a character
+ * progressbar "<color>",<seconds>;
+ */
 BUILDIN_FUNC(progressbar)
 {
 	struct map_session_data * sd;
@@ -20287,6 +20290,60 @@ BUILDIN_FUNC(progressbar)
 	return SCRIPT_CMD_SUCCESS;
 }
 
+/**
+ * Display a progress bar above an NPC
+ * progressbar_npc "<color>",<seconds>{,<"NPC Name">};
+ */
+BUILDIN_FUNC(progressbar_npc){
+	struct npc_data* nd = NULL;
+
+	if( script_hasdata(st, 4) ){
+		const char* name = script_getstr(st, 4);
+
+		nd = npc_name2id(name);
+
+		if( !nd ){
+			ShowError( "buildin_progressbar_npc: NPC \"%s\" was not found.\n", name );
+			return SCRIPT_CMD_FAILURE;
+		}
+	}else{
+		nd = map_id2nd(st->oid);
+	}
+
+	// First call(by function call)
+	if( !nd->progressbar.timeout ){
+		const char *color;
+		int second;
+
+		color = script_getstr(st, 2);
+		second = script_getnum(st, 3);
+
+		if( second < 0 ){
+			ShowError( "buildin_progressbar_npc: negative amount('%d') of seconds is not supported\n", second );
+			return SCRIPT_CMD_FAILURE;
+		}
+
+		// detach the player
+		script_detach_rid(st);
+
+		// sleep for the target amount of time
+		st->state = RERUNLINE;
+		st->sleep.tick = second * 1000;
+		nd->progressbar.timeout = gettick() + second * 1000;
+		nd->progressbar.color = strtol(color, (char **)NULL, 0);
+
+		clif_progressbar_npc_area(nd);
+	// Second call(by timer after sleeping time is over)
+	} else {
+		// Continue the script
+		st->state = RUN;
+		st->sleep.tick = 0;
+		nd->progressbar.timeout = nd->progressbar.color = 0;
+	}
+
+	return SCRIPT_CMD_SUCCESS;
+}
+
 BUILDIN_FUNC(pushpc)
 {
 	uint8 dir;
@@ -23636,6 +23693,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(setfont,"i"),
 	BUILDIN_DEF(areamobuseskill,"siiiiviiiii"),
 	BUILDIN_DEF(progressbar,"si"),
+	BUILDIN_DEF(progressbar_npc, "si?"),
 	BUILDIN_DEF(pushpc,"ii"),
 	BUILDIN_DEF(buyingstore,"i"),
 	BUILDIN_DEF(searchstores,"ii"),