Initial implementation of the goldpc timer

Fixes #6912

Thanks to @Balferian
This commit is contained in:
Lemongrass3110 2022-11-07 01:50:44 +01:00
parent a763ad0629
commit 4b16e4b020
12 changed files with 178 additions and 1 deletions

View File

@ -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
npc/other/goldpc.txt Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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"
};

View File

@ -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"
};

View File

@ -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);

View File

@ -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
*------------------------------------------*/

View File

@ -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 */

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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