Bladeren bron

Initial implementation of the goldpc timer

Fixes #6912

Thanks to @Balferian
Lemongrass3110 2 jaren geleden
bovenliggende
commit
4b16e4b020
12 gewijzigde bestanden met toevoegingen van 178 en 1 verwijderingen
  1. 16 0
      conf/battle/feature.conf
  2. 12 0
      npc/other/goldpc.txt
  3. 1 0
      npc/scripts_athena.conf
  4. 5 0
      src/map/battle.cpp
  5. 5 0
      src/map/battle.hpp
  6. 17 1
      src/map/chrif.cpp
  7. 44 0
      src/map/clif.cpp
  8. 2 0
      src/map/clif.hpp
  9. 4 0
      src/map/clif_packetdb.hpp
  10. 19 0
      src/map/packets.hpp
  11. 49 0
      src/map/pc.cpp
  12. 4 0
      src/map/pc.hpp

+ 16 - 0
conf/battle/feature.conf

@@ -135,3 +135,19 @@ feature.dynamicnpc_rangey: 2
 // Should the dynamic NPCs look into the direction of the player? (Note 1)
 // Default: no
 feature.dynamicnpc_direction: no
+
+// Enable the Gold PC timer? (Note 1)
+// Default: yes
+feature.goldpc_active: yes
+
+// How many seconds does a player have to be online to receive a point?
+// Default: 3600s (1h)
+feature.goldpc_time: 3600
+
+// How many points can a player have at maximum?
+// Default: 300
+feature.goldpc_max_points: 300
+
+// Should being a VIP player double the points a player gets? (Note 1)
+// Default: yes
+feature.goldpc_vip: yes

+ 12 - 0
npc/other/goldpc.txt

@@ -0,0 +1,12 @@
+//===== rAthena Script =======================================
+//= Gold PC Bonus NPC
+//===== Description: =========================================
+//= NPC that can be spawned via the Gold PC Timer Button.
+//===== Changelog: ===========================================
+//= 1.0 Initial release [Lemongrass]
+//============================================================
+
+prontera,0,0,5	script	Goldpoint Manager::GOLDPCCAFE	4_F_02,{
+	// TODO: Implement
+	end;
+}

+ 1 - 0
npc/scripts_athena.conf

@@ -179,6 +179,7 @@ npc: npc/other/comodo_gambling.txt
 npc: npc/other/divorce.txt
 npc: npc/other/fortune.txt
 npc: npc/other/gm_npcs.txt
+npc: npc/other/goldpc.txt
 npc: npc/other/guildpvp.txt
 npc: npc/other/gympass.txt
 npc: npc/other/hugel_bingo.txt

+ 5 - 0
src/map/battle.cpp

@@ -10276,6 +10276,11 @@ static const struct _battle_data {
 	{ "feature.dynamicnpc_rangey",          &battle_config.feature_dynamicnpc_rangey,       2,      0,      INT_MAX,        },
 	{ "feature.dynamicnpc_direction",       &battle_config.feature_dynamicnpc_direction,    0,      0,      1,              },
 
+	{ "feature.goldpc_active",              &battle_config.feature_goldpc_active,           1,      0,      1,              },
+	{ "feature.goldpc_time",                &battle_config.feature_goldpc_time,          3600,      0,   3600,              },
+	{ "feature.goldpc_max_points",          &battle_config.feature_goldpc_max_points,     300,      0,    300,              },
+	{ "feature.goldpc_vip",                 &battle_config.feature_goldpc_vip,              1,      0,      1,              },
+
 #include "../custom/battle_config_init.inc"
 };
 

+ 5 - 0
src/map/battle.hpp

@@ -719,6 +719,11 @@ struct Battle_Config
 	int feature_dynamicnpc_rangey;
 	int feature_dynamicnpc_direction;
 
+	int feature_goldpc_active;
+	int feature_goldpc_time;
+	int feature_goldpc_max_points;
+	int feature_goldpc_vip;
+
 #include "../custom/battle_config_struct.inc"
 };
 

+ 17 - 1
src/map/chrif.cpp

@@ -324,9 +324,25 @@ int chrif_save(struct map_session_data *sd, int flag) {
 	if (sd->premiumStorage.dirty)
 		storage_premiumStorage_save(sd);
 
-	if (flag&CSAVE_QUITTING)
+	if( flag&CSAVE_QUITTING ){
 		sd->state.storage_flag = 0; //Force close it.
 
+		if( sd->goldpc_tid != INVALID_TIMER ){
+			const struct TimerData* td = get_timer( sd->goldpc_tid );
+
+			if( td != nullptr ){
+				// Get the remaining milliseconds until the next reward
+				t_tick remaining = td->tick - gettick();
+
+				// Always round up to full second and a little safety delay
+				remaining += ( remaining % 1000 ) + 2000;
+
+				// Store the seconds that already fully passed
+				pc_setreg2( sd, GOLDPC_SECONDS_VAR, battle_config.feature_goldpc_time - remaining / 1000 );
+			}
+		}
+	}
+
 	//Saving of registry values.
 	if (sd->vars_dirty)
 		intif_saveregistry(sd);

+ 44 - 0
src/map/clif.cpp

@@ -24901,6 +24901,50 @@ void clif_macro_reporter_status(map_session_data &sd, e_macro_report_status styp
 #endif
 }
 
+void clif_goldpc_info( struct map_session_data& sd ){
+#if PACKETVER_MAIN_NUM >= 20140508 || PACKETVER_RE_NUM >= 20140508 || defined(PACKETVER_ZERO)
+	if( battle_config.feature_goldpc_active ){
+		struct PACKET_ZC_GOLDPCCAFE_POINT p = {};
+
+		p.packetType = HEADER_ZC_GOLDPCCAFE_POINT;
+		p.active = sd.goldpc_tid != INVALID_TIMER;
+		if( battle_config.feature_goldpc_vip && pc_isvip( &sd ) ){
+			p.unitPoint = 2;
+		}else{
+			p.unitPoint = 1;
+		}
+		p.point = (int32)pc_readreg2( &sd, GOLDPC_POINT_VAR );
+		// TODO: check if we should send max value, if disabled/max reached
+		p.accumulatePlaySecond = (int32)( 3600 - battle_config.feature_goldpc_time + pc_readreg2( &sd, GOLDPC_SECONDS_VAR ) );
+
+		clif_send( &p, sizeof( p ), &sd.bl, SELF );
+	}
+#endif
+}
+
+void clif_parse_dynamic_npc( int fd, struct map_session_data* sd ){
+#if PACKETVER_MAIN_NUM >= 20140430 || PACKETVER_RE_NUM >= 20140430 || defined(PACKETVER_ZERO)
+	struct PACKET_CZ_DYNAMICNPC_CREATE_REQUEST* p = (struct PACKET_CZ_DYNAMICNPC_CREATE_REQUEST*)RFIFOP( fd, 0 );
+
+	char npcname[NPC_NAME_LENGTH + 1];
+
+	if( strncasecmp( "GOLDPCCAFE", p->nickname, sizeof( p->nickname ) ) == 0 ){
+		safestrncpy( npcname, p->nickname, sizeof( npcname ) );
+	}else{
+		return;
+	}
+
+	struct npc_data* nd = npc_name2id( npcname );
+
+	if( nd == nullptr ){
+		ShowError( "clif_parse_dynamic_npc: Original NPC \"%s\" was not found.\n", npcname );
+		return;
+	}
+
+	npc_duplicate_npc_for_player( *nd, *sd );
+#endif
+}
+
 /*==========================================
  * Main client packet processing function
  *------------------------------------------*/

+ 2 - 0
src/map/clif.hpp

@@ -1243,4 +1243,6 @@ void clif_macro_detector_status(map_session_data &sd, e_macro_detect_status styp
 void clif_macro_reporter_select(map_session_data &sd, const std::vector<uint32> &aid_list);
 void clif_macro_reporter_status(map_session_data &sd, e_macro_report_status stype);
 
+void clif_goldpc_info( struct map_session_data& sd );
+
 #endif /* CLIF_HPP */

+ 4 - 0
src/map/clif_packetdb.hpp

@@ -2136,6 +2136,10 @@
 	packet(0x09DA,-1);
 #endif
 
+#if PACKETVER_MAIN_NUM >= 20140430 || PACKETVER_RE_NUM >= 20140430 || defined(PACKETVER_ZERO)
+	parseable_packet( HEADER_CZ_DYNAMICNPC_CREATE_REQUEST, sizeof( PACKET_CZ_DYNAMICNPC_CREATE_REQUEST ), clif_parse_dynamic_npc, 0 );
+#endif
+
 // 2014-10-08Ragexe
 #if PACKETVER >= 20141008
 	parseable_packet(0x9FB, -1, clif_parse_pet_evolution, 2, 4); // CZ_PET_EVOLUTION

+ 19 - 0
src/map/packets.hpp

@@ -367,6 +367,23 @@ struct PACKET_CZ_REQ_CHANGE_MEMBERPOS{
 	struct PACKET_CZ_REQ_CHANGE_MEMBERPOS_sub list[];
 } __attribute__((packed));
 
+#if PACKETVER_MAIN_NUM >= 20140508 || PACKETVER_RE_NUM >= 20140508 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_GOLDPCCAFE_POINT{
+	int16 packetType;
+	int8 active;
+	int8 unitPoint;
+	int32 point;
+	int32 accumulatePlaySecond;
+} __attribute__((packed));
+#elif PACKETVER_MAIN_NUM >= 20140430 || PACKETVER_RE_NUM >= 20140430
+	// TODO: find difference (1byte) priority low...
+#endif
+
+struct PACKET_CZ_DYNAMICNPC_CREATE_REQUEST{
+	int16 packetType;
+	char nickname[NAME_LENGTH];
+} __attribute__((packed));
+
 // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
 #if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 )
 	#pragma pack( pop )
@@ -409,6 +426,8 @@ DEFINE_PACKET_HEADER(ZC_NOTIFY_BARGAIN_SALE_SELLING, 0x9b2)
 DEFINE_PACKET_HEADER(ZC_NOTIFY_BARGAIN_SALE_CLOSE, 0x9b3)
 DEFINE_PACKET_HEADER(ZC_ACK_COUNT_BARGAIN_SALE_ITEM, 0x9c4)
 DEFINE_PACKET_HEADER(ZC_ACK_GUILDSTORAGE_LOG, 0x9da)
+DEFINE_PACKET_HEADER(ZC_GOLDPCCAFE_POINT, 0xa15)
+DEFINE_PACKET_HEADER(CZ_DYNAMICNPC_CREATE_REQUEST, 0xa16)
 DEFINE_PACKET_HEADER(CZ_REQ_APPLY_BARGAIN_SALE_ITEM2, 0xa3d)
 DEFINE_PACKET_HEADER(CZ_REQ_STYLE_CHANGE, 0xa46)
 DEFINE_PACKET_HEADER(ZC_STYLE_CHANGE_RES, 0xa47)

+ 49 - 0
src/map/pc.cpp

@@ -1972,6 +1972,47 @@ bool pc_set_hate_mob(struct map_session_data *sd, int pos, struct block_list *bl
 	return true;
 }
 
+TIMER_FUNC(pc_goldpc_update){
+	struct map_session_data* sd = map_id2sd( id );
+
+	if( sd == nullptr ){
+		return 0;
+	}
+
+	sd->goldpc_tid = INVALID_TIMER;
+
+	// Check if feature is still active
+	if( !battle_config.feature_goldpc_active ){
+		return 0;
+	}
+
+	// TODO: add mapflag to disable?
+
+	int32 points = (int32)pc_readreg2( sd, GOLDPC_POINT_VAR );
+
+	if( points < battle_config.feature_goldpc_max_points ){
+		if( battle_config.feature_goldpc_vip && pc_isvip( sd ) ){
+			points += 2;
+		}else{
+			points += 1;
+		}
+
+		points = std::min( points, battle_config.feature_goldpc_max_points );
+
+		pc_setreg2( sd, GOLDPC_POINT_VAR, points );
+		pc_setreg2( sd, GOLDPC_SECONDS_VAR, 0 );
+
+		if( points < battle_config.feature_goldpc_max_points ){
+			sd->goldpc_tid = add_timer( gettick() + battle_config.feature_goldpc_time * 1000, pc_goldpc_update, sd->bl.id, NULL );
+		}
+
+		// Update the client
+		clif_goldpc_info( *sd );
+	}
+
+	return 0;
+}
+
 /*==========================================
  * Invoked once after the char/account/account2 registry variables are received. [Skotlex]
  * We didn't receive item information at this point so DO NOT attempt to do item operations here.
@@ -2080,6 +2121,13 @@ void pc_reg_received(struct map_session_data *sd)
 	clif_instance_info( *sd );
 #endif
 
+	if( battle_config.feature_goldpc_active ){
+		sd->goldpc_tid = add_timer( gettick() + ( battle_config.feature_goldpc_time - pc_readreg2( sd, GOLDPC_SECONDS_VAR ) ) * 1000, pc_goldpc_update, sd->bl.id, NULL );
+		clif_goldpc_info( *sd );
+	}else{
+		sd->goldpc_tid = INVALID_TIMER;
+	}
+
 	// pet
 	if (sd->status.pet_id > 0)
 		intif_request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id);
@@ -15452,6 +15500,7 @@ void do_init_pc(void) {
 	add_timer_func_list(pc_autotrade_timer, "pc_autotrade_timer");
 	add_timer_func_list(pc_on_expire_active, "pc_on_expire_active");
 	add_timer_func_list(pc_macro_detector_timeout, "pc_macro_detector_timeout");
+	add_timer_func_list( pc_goldpc_update, "pc_goldpc_update" );
 
 	add_timer(gettick() + autosave_interval, pc_autosave, 0, 0);
 

+ 4 - 0
src/map/pc.hpp

@@ -63,6 +63,8 @@ enum sc_type : int16;
 #define ATTENDANCE_DATE_VAR "#AttendanceDate"
 #define ATTENDANCE_COUNT_VAR "#AttendanceCounter"
 #define ACHIEVEMENTLEVEL "AchievementLevel"
+#define GOLDPC_POINT_VAR "Goldpc_Points"
+#define GOLDPC_SECONDS_VAR "Goldpc_Seconds"
 
 //Total number of classes (for data storage)
 #define CLASS_COUNT (JOB_MAX - JOB_NOVICE_HIGH + JOB_MAX_BASIC)
@@ -931,6 +933,8 @@ struct map_session_data {
 	} captcha_upload;
 
 	s_macro_detect macro_detect;
+
+	int goldpc_tid;
 };
 
 extern struct eri *pc_sc_display_ers; /// Player's SC display table