Initial Release of Attendance Feature (#3297)
Thanks to @secretdataz and @aleos89 for their help. Thanks to @Haikenz and @admkakaroto for testing. Thanks to @Daegaladh for his ideas.
This commit is contained in:
parent
030443c9d3
commit
a5588dd9ab
@ -70,3 +70,7 @@ feature.achievement: on
|
||||
// Homunculues Autofeeding (Note 1)
|
||||
// Requires: 2017-09-20bRagexeRE or later
|
||||
feature.homunculus_autofeed: off
|
||||
|
||||
// Attendance System (Note 1)
|
||||
// Requires: 2018-03-07bRagexeRE or later
|
||||
feature.attendance: off
|
||||
|
@ -94,6 +94,7 @@ groups: (
|
||||
can_trade: true
|
||||
can_party: true
|
||||
command_enable: true
|
||||
attendance: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -135,6 +136,7 @@ groups: (
|
||||
langtype: true
|
||||
}
|
||||
permissions: {
|
||||
attendance: false
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -105,11 +105,13 @@ minsave_time: 100
|
||||
// 32: After successfully submitting an item for auction
|
||||
// 64: After successfully get/delete/complete a quest
|
||||
// 128: After every bank transaction (deposit/withdraw)
|
||||
// 256: After every attendance reward
|
||||
// 4095: Always
|
||||
// NOTE: These settings decrease the chance of dupes/lost items when there's a
|
||||
// server crash at the expense of increasing the map/char server lag. If your
|
||||
// server rarely crashes, but experiences interserver lag, you may want to set
|
||||
// these off.
|
||||
save_settings: 255
|
||||
save_settings: 4095
|
||||
|
||||
// Message of the day file, when a character logs on, this message is displayed.
|
||||
motd_txt: conf/motd.txt
|
||||
|
@ -843,7 +843,16 @@
|
||||
786: The guild does not have a guild storage.
|
||||
787: You do not have permission to use the guild storage.
|
||||
|
||||
//788-899 free
|
||||
// Attendance
|
||||
// Mail sender: Officer
|
||||
788: <MSG>3455</MSG>
|
||||
// Mail title: %dday attendance has been paid.
|
||||
789: <MSG>3456,%d</MSG>
|
||||
// Mail body: %dday attendance has been paid.
|
||||
790: <MSG>3456,%d</MSG>
|
||||
791: You are not allowed to use the attendance system.
|
||||
|
||||
//792-899 free
|
||||
|
||||
//------------------------------------
|
||||
// More atcommands message
|
||||
|
3
db/import-tmpl/attendance.yml
Normal file
3
db/import-tmpl/attendance.yml
Normal file
@ -0,0 +1,3 @@
|
||||
Header:
|
||||
Type: ATTENDANCE_CONF
|
||||
Version: 1
|
3
db/pre-re/attendance.yml
Normal file
3
db/pre-re/attendance.yml
Normal file
@ -0,0 +1,3 @@
|
||||
Header:
|
||||
Type: ATTENDANCE_CONF
|
||||
Version: 1
|
61
db/re/attendance.yml
Normal file
61
db/re/attendance.yml
Normal file
@ -0,0 +1,61 @@
|
||||
Header:
|
||||
Type: ATTENDANCE_CONF
|
||||
Version: 1
|
||||
|
||||
Attendance:
|
||||
- Start: 20180502
|
||||
End: 20180529
|
||||
Rewards:
|
||||
- Day: 1
|
||||
ItemId: 22979
|
||||
- Day: 2
|
||||
ItemId: 6316
|
||||
- Day: 3
|
||||
ItemId: 12265
|
||||
Amount: 5
|
||||
- Day: 4
|
||||
ItemId: 23047
|
||||
Amount: 5
|
||||
- Day: 5
|
||||
ItemId: 23038
|
||||
- Day: 6
|
||||
ItemId: 23043
|
||||
- Day: 7
|
||||
ItemId: 23340
|
||||
Amount: 3
|
||||
- Day: 8
|
||||
ItemId: 12516
|
||||
Amount: 5
|
||||
- Day: 9
|
||||
ItemId: 23307
|
||||
Amount: 5
|
||||
- Day: 10
|
||||
ItemId: 12610
|
||||
- Day: 11
|
||||
ItemId: 14533
|
||||
Amount: 2
|
||||
- Day: 12
|
||||
ItemId: 23012
|
||||
Amount: 3
|
||||
- Day: 13
|
||||
ItemId: 23048
|
||||
Amount: 5
|
||||
- Day: 14
|
||||
ItemId: 12264
|
||||
Amount: 5
|
||||
- Day: 15
|
||||
ItemId: 23046
|
||||
Amount: 5
|
||||
- Day: 16
|
||||
ItemId: 12515
|
||||
Amount: 5
|
||||
- Day: 17
|
||||
ItemId: 12522
|
||||
Amount: 5
|
||||
- Day: 18
|
||||
ItemId: 12523
|
||||
Amount: 5
|
||||
- Day: 19
|
||||
ItemId: 6234
|
||||
- Day: 20
|
||||
ItemId: 22845
|
@ -6827,6 +6827,7 @@
|
||||
12607,Lolli_Pop_Box,Delicious Lollipop Box,11,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
12608,Splendid_Box2,Splendid Box2,11,20,,100,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
12609,Old_Ore_Box,Old Ore Box,2,20,,100,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Old_Ore_Box); },{},{}
|
||||
12610,Mysterious_Egg,Mysterious Egg,2,,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
12612,Old_Coin_Pocket,Old Coin Bag,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Old_Coin_Pocket); },{},{}
|
||||
12613,High_Coin_Pocket,Improved Coin Bag,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_High_Coin_Pocket); },{},{}
|
||||
12614,Mid_Coin_Pocket,Intermediate Coin Bag,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Mid_Coin_Pocket); },{},{}
|
||||
@ -9277,7 +9278,7 @@
|
||||
17181,Jan_Groove_Box,Jan Groove Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
17184,3rd_Test_Pass_Box,3rd Test Pass Box,18,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 6583,1; },{},{}
|
||||
17203,Free_Pass_Box,Free Pass Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
17204,Mysterious_Egg,Shining Egg,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,1,,,{ getgroupitem(IG_Mysterious_Egg); },{},{}
|
||||
17204,Shining_Egg,Shining Egg,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,1,,,{ getgroupitem(IG_Shining_Egg); },{},{}
|
||||
17207,Idn_Heart_Scroll,Idn Heart Scroll,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Idn_Heart_Scroll); },{},{}
|
||||
17209,Tw_Rainbow_Scroll,Tw Rainbow Scroll,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Tw_Rainbow_Scroll); },{},{}
|
||||
17210,Tw_Red_Scroll,Tw Red Scroll,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Tw_Red_Scroll); },{},{}
|
||||
@ -11155,6 +11156,7 @@
|
||||
22782,PC_Bang_Wooden_Box,PC Bang Wooden Box,2,10,,200,,,,0,0xFFFFFFFF,63,2,,,1,,,{ getitem 547,30; /*No Info*/},{},{}
|
||||
22783,PC_Bang_Golden_Box,PC Bang Golden Box,2,10,,200,,,,0,0xFFFFFFFF,63,2,,,1,,,{ getitem 547,1; getitem 985,10; /*No Info*/},{},{}
|
||||
22784,PC_Bang_Platinum_Box,PC Bang Platinum Box,2,10,,200,,,,0,0xFFFFFFFF,63,2,,,1,,,{ getitem 547,1; getitem 12017,10; getitem 678,12; /*No Info*/},{},{}
|
||||
22979,C_Battle_Gum_2,[Sale] Battle Manual and Bubble Gum,2,,,0,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
22802,Safe_to_6_Equipment_Certificate,Safe to 6 Equipment Certificate,3,10,,10,,,,,,,,,,,,,{},{},{}
|
||||
22808,Special_Gift_Box,Special Gift Box,2,10,,100,,,,,,,,,,,,,{},{},{}
|
||||
22812,Sealed_Dracula_Scroll,Sealed Dracula Scroll,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,1,,,{ getitem callfunc("F_Rand",6228,6232,22813,19937,17314, 6635),1; },{},{}
|
||||
@ -11213,6 +11215,13 @@
|
||||
22984,Kahluna_Milk,Kahluna Milk,0,6,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ sc_start SC_DORAM_BUF_01, 180000, 0; },{},{}
|
||||
22985,Basil,Basil,0,10,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ sc_start SC_DORAM_BUF_02, 180000, 0; },{},{}
|
||||
//
|
||||
23012,S_Small_Mana_Potion,[Sale] Small Mana Potion,2,,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
23038,S_Slim_White_Box,[Sale] Slim White Potion Box,2,,,0,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
23043,S_Seed_Of_Yggdrasil_Box,[Sale] Yggdrasil Seed Box,2,,,0,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
23046,S_Mystic_Powder,[Sale] Mystic Powder,2,,,0,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
23047,S_Blessing_Tyr,[Sale] Blessing of Tyr,2,,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
23048,S_Resilience_Potion,[Sale] Resilience Enhancement Potion,2,,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
//
|
||||
23123,Bullet_Case_Flare,Flare Bullet Cartridge,2,10,,250,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 13228,500; },{},{}
|
||||
23124,Bullet_Case_Lighting,Lightning Bullet Cartridge,2,10,,250,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 13229,500; },{},{}
|
||||
23125,Bullet_Case_Ice,Ice Bullet Cartridge,2,10,,250,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 13230,500; },{},{}
|
||||
@ -11227,6 +11236,9 @@
|
||||
23196,Agust_Lucky_Scroll,Shining Blue Lucky Egg,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,1,,,{ getgroupitem(IG_Agust_Lucky_Scroll); },{},{}
|
||||
//
|
||||
23277,Mado_Box,Emergency Magic Gear,2,10000,,3000,,,,,0x00000400,56,2,,,100,,,{ setmadogear 1; },{},{}
|
||||
//
|
||||
23307,S_Shining_Def_Scroll,[Sale] Shining Defense Scroll,2,,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
23340,S_Megaphone,[Sale] Megaphone,2,,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
//===================================================================
|
||||
// Shadow Equipments
|
||||
//===================================================================
|
||||
|
@ -4473,23 +4473,23 @@ IG_Something_Candy_Holder,22067,1,1 // 1x Witch Shoes
|
||||
IG_Something_Candy_Holder,22669,5,1 // 1x October Spooky Trade Box
|
||||
IG_Something_Candy_Holder,22670,1,1 // 1x DARK INVITATION
|
||||
|
||||
// Mysterious_Egg
|
||||
IG_Mysterious_Egg,12259,200,1,1,0,0,0 // 1x Miracle_Medicine
|
||||
IG_Mysterious_Egg,5374,1,1,1,0,0,0 // 1x L_Magestic_Goat
|
||||
IG_Mysterious_Egg,5254,99,1,1,0,0,0 // 1x Deviling_Hat
|
||||
IG_Mysterious_Egg,12246,99,1,1,0,0,0 // 1x Magic_Card_Album
|
||||
IG_Mysterious_Egg,4302,1,1,1,0,0,0 // 1x Tao_Gunka_Card
|
||||
IG_Mysterious_Egg,5474,200,1,1,0,0,0 // 1x Notice_Board
|
||||
IG_Mysterious_Egg,2554,1,1,1,0,0,0 // 1x Piece_Of_Angent_Skin
|
||||
IG_Mysterious_Egg,17001,1099,1,1,0,0,0 // 1x Wander_Man_Box10
|
||||
IG_Mysterious_Egg,12903,1000,1,1,0,0,0 // 1x Str_Dish_Box
|
||||
IG_Mysterious_Egg,12922,1100,1,1,0,0,0 // 1x Token_Of_Siegfried_Box
|
||||
IG_Mysterious_Egg,16755,1200,1,1,0,0,0 // 1x Unbreak_Def_Box
|
||||
IG_Mysterious_Egg,12909,800,1,1,0,0,0 // 1x Kafra_Card_Box
|
||||
IG_Mysterious_Egg,14232,800,1,1,0,0,0 // 1x Yggdrasilberry_Box_
|
||||
IG_Mysterious_Egg,12361,1000,2,1,0,0,0 // 2x Delicious_Shaved_Ice
|
||||
IG_Mysterious_Egg,12910,1100,1,1,0,0,0 // 1x Giant_Fly_Wing_Box
|
||||
IG_Mysterious_Egg,16753,1300,1,1,0,0,0 // 1x Unbreak_Weap_Box
|
||||
// Shining Egg
|
||||
IG_Shining_Egg,12259,200,1,1,0,0,0 // 1x Miracle_Medicine
|
||||
IG_Shining_Egg,5374,1,1,1,0,0,0 // 1x L_Magestic_Goat
|
||||
IG_Shining_Egg,5254,99,1,1,0,0,0 // 1x Deviling_Hat
|
||||
IG_Shining_Egg,12246,99,1,1,0,0,0 // 1x Magic_Card_Album
|
||||
IG_Shining_Egg,4302,1,1,1,0,0,0 // 1x Tao_Gunka_Card
|
||||
IG_Shining_Egg,5474,200,1,1,0,0,0 // 1x Notice_Board
|
||||
IG_Shining_Egg,2554,1,1,1,0,0,0 // 1x Piece_Of_Angent_Skin
|
||||
IG_Shining_Egg,17001,1099,1,1,0,0,0 // 1x Wander_Man_Box10
|
||||
IG_Shining_Egg,12903,1000,1,1,0,0,0 // 1x Str_Dish_Box
|
||||
IG_Shining_Egg,12922,1100,1,1,0,0,0 // 1x Token_Of_Siegfried_Box
|
||||
IG_Shining_Egg,16755,1200,1,1,0,0,0 // 1x Unbreak_Def_Box
|
||||
IG_Shining_Egg,12909,800,1,1,0,0,0 // 1x Kafra_Card_Box
|
||||
IG_Shining_Egg,14232,800,1,1,0,0,0 // 1x Yggdrasilberry_Box_
|
||||
IG_Shining_Egg,12361,1000,2,1,0,0,0 // 2x Delicious_Shaved_Ice
|
||||
IG_Shining_Egg,12910,1100,1,1,0,0,0 // 1x Giant_Fly_Wing_Box
|
||||
IG_Shining_Egg,16753,1300,1,1,0,0,0 // 1x Unbreak_Weap_Box
|
||||
|
||||
// Agust_Lucky_Scroll
|
||||
IG_Agust_Lucky_Scroll,4365,1,1,1,1,0,0 // 1x B_Katrinn_Card
|
||||
|
@ -1440,7 +1440,7 @@
|
||||
12596,475,100 // Magic_Candy
|
||||
12600,507,100 // Treasure_Box_Scroll
|
||||
12607,507,100 // Lolli_Pop_Box
|
||||
//12610,475,100 //
|
||||
12610,475,100 // Mysterious_Egg
|
||||
12622,507,100 // Boarding_Halter
|
||||
12625,475,100 // Sapa_Feat_Cert_Pack
|
||||
12633,475,100 // Malang_Cat_Can
|
||||
@ -3869,6 +3869,15 @@
|
||||
//22950,475,100 //
|
||||
//22951,475,100 //
|
||||
//22952,475,100 //
|
||||
22979,475,100 // C_Battle_Gum_2
|
||||
23012,475,100 // S_Small_Mana_Potion
|
||||
23038,475,100 // S_Slim_White_Box
|
||||
23043,475,100 // S_Seed_Of_Yggdrasil_Box
|
||||
23046,475,100 // S_Mystic_Powder
|
||||
23047,475,100 // S_Blessing_Tyr
|
||||
23048,475,100 // S_Resilience_Potion
|
||||
23307,475,100 // S_Shining_Def_Scroll
|
||||
23340,475,100 // S_Megaphone
|
||||
23177,475,100 // Kafra_Card_
|
||||
23196,475,100 // Shining_Blue_Lucky_Egg
|
||||
25043,499,100 // Thorny_Vine_Flute
|
||||
|
@ -3135,6 +3135,7 @@ DT_DAYOFMONTH - Day of the current month
|
||||
DT_MONTH - Month (constants for JANUARY to DECEMBER are available)
|
||||
DT_YEAR - Year
|
||||
DT_DAYOFYEAR - Day of the year
|
||||
DT_YYYYMMDD - current date in the form YYYYMMDD
|
||||
|
||||
It will only return numbers. If another type is supplied -1 will be returned.
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "cbasetypes.hpp"
|
||||
|
||||
// Class used to perform time measurement
|
||||
class cScopeTimer {
|
||||
struct sPimpl; //this is to avoid long compilation time
|
||||
@ -20,6 +22,10 @@ int levenshtein( const std::string &s1, const std::string &s2 );
|
||||
|
||||
namespace rathena {
|
||||
namespace util {
|
||||
template <typename K, typename V> bool map_exists( std::map<K,V>& map, K key ){
|
||||
return map.find( key ) != map.end();
|
||||
}
|
||||
|
||||
template <typename K, typename V> V* map_find( std::map<K,V>& map, K key ){
|
||||
auto it = map.find( key );
|
||||
|
||||
|
@ -8562,6 +8562,7 @@ static const struct _battle_data {
|
||||
{ "feature.homunculus_autofeed", &battle_config.feature_homunculus_autofeed, 1, 0, 1, },
|
||||
{ "summoner_trait", &battle_config.summoner_trait, 3, 0, 3, },
|
||||
{ "homunculus_autofeed_always", &battle_config.homunculus_autofeed_always, 1, 0, 1, },
|
||||
{ "feature.attendance", &battle_config.feature_attendance, 1, 0, 1, },
|
||||
|
||||
#include "../custom/battle_config_init.inc"
|
||||
};
|
||||
@ -8699,6 +8700,13 @@ void battle_adjust_conf()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PACKETVER < 20180307
|
||||
if( battle_config.feature_attendance ){
|
||||
ShowWarning("conf/battle/feature.conf attendance system is enabled but it requires PACKETVER 2018-03-07 or newer, disabling...\n");
|
||||
battle_config.feature_attendance = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CELL_NOSTACK
|
||||
if (battle_config.custom_cell_stack_limit != 1)
|
||||
ShowWarning("Battle setting 'custom_cell_stack_limit' takes no effect as this server was compiled without Cell Stack Limit support.\n");
|
||||
|
@ -643,6 +643,7 @@ struct Battle_Config
|
||||
int feature_homunculus_autofeed;
|
||||
int summoner_trait;
|
||||
int homunculus_autofeed_always;
|
||||
int feature_attendance;
|
||||
|
||||
#include "../custom/battle_config_struct.inc"
|
||||
};
|
||||
|
@ -9930,6 +9930,21 @@ void clif_msg_skill(struct map_session_data* sd, uint16 skill_id, int msg_id)
|
||||
WFIFOSET(fd, packet_len(0x7e6));
|
||||
}
|
||||
|
||||
/// Displays msgstringtable.txt string in a color. (ZC_MSG_COLOR).
|
||||
/// 09cd <msg id>.W <color>.L
|
||||
void clif_msg_color( struct map_session_data *sd, uint16 msg_id, uint32 color ){
|
||||
nullpo_retv(sd);
|
||||
|
||||
int fd = sd->fd;
|
||||
|
||||
WFIFOHEAD(fd, packet_len(0x9cd));
|
||||
WFIFOW(fd, 0) = 0x9cd;
|
||||
WFIFOW(fd, 2) = msg_id;
|
||||
WFIFOL(fd, 4) = color;
|
||||
|
||||
WFIFOSET(fd, packet_len(0x9cd));
|
||||
}
|
||||
|
||||
/// Validates one global/guild/party/whisper message packet and tries to recognize its components.
|
||||
/// Returns true if the packet was parsed successfully.
|
||||
/// Formats: false - <packet id>.w <packet len>.w (<name> : <message>).?B 00
|
||||
@ -20285,6 +20300,56 @@ void clif_parse_changedress( int fd, struct map_session_data* sd ){
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Opens an UI window of the given type and initializes it with the given data
|
||||
/// 0AE2 <type>.B <data>.L
|
||||
void clif_ui_open( struct map_session_data *sd, enum out_ui_type ui_type, int32 data ){
|
||||
nullpo_retv(sd);
|
||||
|
||||
int fd = sd->fd;
|
||||
|
||||
WFIFOHEAD(fd,packet_len(0xae2));
|
||||
WFIFOW(fd,0) = 0xae2;
|
||||
WFIFOB(fd,2) = ui_type;
|
||||
WFIFOL(fd,3) = data;
|
||||
WFIFOSET(fd,packet_len(0xae2));
|
||||
}
|
||||
|
||||
/// Request to open an UI window of the given type
|
||||
/// 0A68 <type>.B
|
||||
void clif_parse_open_ui( int fd, struct map_session_data* sd ){
|
||||
switch( RFIFOB(fd,2) ){
|
||||
case IN_UI_ATTENDANCE:
|
||||
if( !pc_has_permission( sd, PC_PERM_ATTENDANCE ) ){
|
||||
clif_messagecolor( &sd->bl, color_table[COLOR_RED], msg_txt( sd, 791 ), false, SELF ); // You are not allowed to use the attendance system.
|
||||
}else if( pc_attendance_enabled() ){
|
||||
clif_ui_open( sd, OUT_UI_ATTENDANCE, pc_attendance_counter( sd ) );
|
||||
}else{
|
||||
clif_msg_color( sd, MSG_ATTENDANCE_DISABLED, color_table[COLOR_RED] );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Response for attedance request
|
||||
/// 0AF0 <unknown>.L <data>.L
|
||||
void clif_attendence_response( struct map_session_data *sd, int32 data ){
|
||||
nullpo_retv(sd);
|
||||
|
||||
int fd = sd->fd;
|
||||
|
||||
WFIFOHEAD(fd,packet_len(0xAF0));
|
||||
WFIFOW(fd,0) = 0xAF0;
|
||||
WFIFOL(fd,2) = 0;
|
||||
WFIFOL(fd,6) = data;
|
||||
WFIFOSET(fd,packet_len(0xAF0));
|
||||
}
|
||||
|
||||
/// Request from the client to retrieve today's attendance reward
|
||||
/// 0AEF
|
||||
void clif_parse_attendance_request( int fd, struct map_session_data* sd ){
|
||||
pc_attendance_claim_reward(sd);
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* Main client packet processing function
|
||||
*------------------------------------------*/
|
||||
|
@ -510,6 +510,7 @@ enum clif_messages : uint16_t {
|
||||
SKILL_NEED_REVOLVER = 0x9fd,
|
||||
SKILL_NEED_HOLY_BULLET = 0x9fe,
|
||||
SKILL_NEED_GRENADE = 0xa01,
|
||||
MSG_ATTENDANCE_DISABLED = 0xd92,
|
||||
};
|
||||
|
||||
enum e_personalinfo : uint8_t {
|
||||
@ -1075,4 +1076,16 @@ void clif_achievement_list_all(struct map_session_data *sd);
|
||||
void clif_achievement_update(struct map_session_data *sd, struct achievement *ach, int count);
|
||||
void clif_achievement_reward_ack(int fd, unsigned char result, int ach_id);
|
||||
|
||||
/// Attendance System
|
||||
enum in_ui_type : int8 {
|
||||
IN_UI_ATTENDANCE = 5
|
||||
};
|
||||
|
||||
enum out_ui_type : int8 {
|
||||
OUT_UI_ATTENDANCE = 7
|
||||
};
|
||||
|
||||
void clif_ui_open( struct map_session_data *sd, enum out_ui_type ui_type, int32 data );
|
||||
void clif_attendence_response( struct map_session_data *sd, int32 data );
|
||||
|
||||
#endif /* _CLIF_HPP_ */
|
||||
|
@ -2143,6 +2143,7 @@
|
||||
parseable_packet(0x096E,-1,clif_parse_merge_item_req,2,4); // CZ_REQ_MERGE_ITEM
|
||||
ack_packet(ZC_ACK_MERGE_ITEM,0x096F,7,2,4,6,7); // ZC_ACK_MERGE_ITEM
|
||||
parseable_packet(0x0974,2,clif_parse_merge_item_cancel,0); // CZ_CANCEL_MERGE_ITEM
|
||||
packet(0x9CD,8); // ZC_MSG_COLOR
|
||||
#endif
|
||||
|
||||
// 2013-08-21bRagexe
|
||||
@ -2381,9 +2382,9 @@
|
||||
|
||||
// 2018-03-07bRagexeRE
|
||||
#if PACKETVER >= 20180307
|
||||
parseable_packet(0x0A68,3,clif_parse_dull,0);
|
||||
parseable_packet(0x0A68,3,clif_parse_open_ui,2);
|
||||
packet(0x0AE2,7);
|
||||
parseable_packet(0x0AEF,2,clif_parse_dull,0);
|
||||
parseable_packet(0x0AEF,2,clif_parse_attendance_request,0);
|
||||
packet(0x0AF0,10);
|
||||
#endif
|
||||
|
||||
|
@ -123,6 +123,8 @@ int date_get( enum e_date_type type )
|
||||
return date_get_year();
|
||||
case DT_DAYOFYEAR:
|
||||
return date_get_dayofyear();
|
||||
case DT_YYYYMMDD:
|
||||
return date_get( DT_YEAR ) * 10000 + date_get( DT_MONTH ) * 100 + date_get(DT_DAYOFMONTH);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ enum e_date_type{
|
||||
DT_MONTH,
|
||||
DT_YEAR,
|
||||
DT_DAYOFYEAR,
|
||||
DT_YYYYMMDD,
|
||||
DT_MAX
|
||||
};
|
||||
|
||||
|
@ -714,7 +714,7 @@ enum e_random_item_group {
|
||||
IG_COSTAMA_EGG29,
|
||||
IG_INK_BALL,
|
||||
IG_SOMETHING_CANDY_HOLDER,
|
||||
IG_MYSTERIOUS_EGG,
|
||||
IG_SHINING_EGG,
|
||||
IG_AGUST_LUCKY_SCROLL,
|
||||
IG_ELEMENT,
|
||||
IG_POISON,
|
||||
|
@ -292,6 +292,7 @@
|
||||
<Copy SourceFiles="$(SolutionDir)conf\msg_conf\import-tmpl\map_msg_tha_conf.txt" DestinationFolder="$(SolutionDir)conf\msg_conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\msg_conf\import\map_msg_tha_conf.txt')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\abra_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\abra_db.txt')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\achievement_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\achievement_db.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\attendance.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\attendance.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\attr_fix.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\attr_fix.txt')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\castle_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\castle_db.txt')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\const.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\const.txt')" />
|
||||
|
@ -125,7 +125,7 @@ int map_port=0;
|
||||
|
||||
int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
|
||||
int minsave_interval = 100;
|
||||
unsigned char save_settings = CHARSAVE_ALL;
|
||||
int16 save_settings = CHARSAVE_ALL;
|
||||
bool agit_flag = false;
|
||||
bool agit2_flag = false;
|
||||
bool agit3_flag = false;
|
||||
|
@ -753,7 +753,7 @@ extern int map_num;
|
||||
|
||||
extern int autosave_interval;
|
||||
extern int minsave_interval;
|
||||
extern unsigned char save_settings;
|
||||
extern int16 save_settings;
|
||||
extern int night_flag; // 0=day, 1=night [Yor]
|
||||
extern int enable_spy; //Determines if @spy commands are active.
|
||||
|
||||
@ -780,16 +780,17 @@ extern struct s_map_default map_default;
|
||||
|
||||
/// Type of 'save_settings'
|
||||
enum save_settings_type {
|
||||
CHARSAVE_NONE = 0,
|
||||
CHARSAVE_TRADE = 0x01, /// After trading
|
||||
CHARSAVE_VENDING = 0x02, /// After vending (open/transaction)
|
||||
CHARSAVE_STORAGE = 0x04, /// After closing storage/guild storage.
|
||||
CHARSAVE_PET = 0x08, /// After hatching/returning to egg a pet.
|
||||
CHARSAVE_MAIL = 0x10, /// After successfully sending a mail with attachment
|
||||
CHARSAVE_AUCTION = 0x20, /// After successfully submitting an item for auction
|
||||
CHARSAVE_QUEST = 0x40, /// After successfully get/delete/complete a quest
|
||||
CHARSAVE_BANK = 0x80, /// After every bank transaction (deposit/withdraw)
|
||||
CHARSAVE_ALL = 0xFF,
|
||||
CHARSAVE_NONE = 0x000, /// Never
|
||||
CHARSAVE_TRADE = 0x001, /// After trading
|
||||
CHARSAVE_VENDING = 0x002, /// After vending (open/transaction)
|
||||
CHARSAVE_STORAGE = 0x004, /// After closing storage/guild storage.
|
||||
CHARSAVE_PET = 0x008, /// After hatching/returning to egg a pet.
|
||||
CHARSAVE_MAIL = 0x010, /// After successfully sending a mail with attachment
|
||||
CHARSAVE_AUCTION = 0x020, /// After successfully submitting an item for auction
|
||||
CHARSAVE_QUEST = 0x040, /// After successfully get/delete/complete a quest
|
||||
CHARSAVE_BANK = 0x080, /// After every bank transaction (deposit/withdraw)
|
||||
CHARSAVE_ATTENDANCE = 0x100, /// After every attendence reward
|
||||
CHARSAVE_ALL = 0xFFF, /// Always
|
||||
};
|
||||
|
||||
// users
|
||||
|
283
src/map/pc.cpp
283
src/map/pc.cpp
@ -3,9 +3,14 @@
|
||||
|
||||
#include "pc.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include "../common/cbasetypes.hpp"
|
||||
#include "../common/core.hpp" // get_svn_revision()
|
||||
#include "../common/ers.hpp" // ers_destroy
|
||||
@ -17,6 +22,7 @@
|
||||
#include "../common/socket.hpp" // session[]
|
||||
#include "../common/strlib.hpp" // safestrncpy()
|
||||
#include "../common/timer.hpp"
|
||||
#include "../common/utilities.hpp"
|
||||
#include "../common/utils.hpp"
|
||||
|
||||
#include "achievement.hpp"
|
||||
@ -53,7 +59,10 @@
|
||||
#include "unit.hpp" // unit_stop_attack(), unit_stop_walking()
|
||||
#include "vending.hpp" // struct s_vending
|
||||
|
||||
using namespace rathena;
|
||||
|
||||
int pc_split_atoui(char* str, unsigned int* val, char sep, int max);
|
||||
static inline bool pc_attendance_rewarded_today( struct map_session_data* sd );
|
||||
|
||||
#define PVP_CALCRANK_INTERVAL 1000 // PVP calculation interval
|
||||
#define MAX_LEVEL_BASE_EXP 99999999 ///< Max Base EXP for player on Max Base Level
|
||||
@ -82,6 +91,19 @@ struct fame_list taekwon_fame_list[MAX_FAME_LIST];
|
||||
|
||||
struct s_job_info job_info[CLASS_COUNT];
|
||||
|
||||
struct s_attendance_reward{
|
||||
uint16 item_id;
|
||||
uint16 amount;
|
||||
};
|
||||
|
||||
struct s_attendance_period{
|
||||
uint32 start;
|
||||
uint32 end;
|
||||
std::map<int,struct s_attendance_reward> rewards;
|
||||
};
|
||||
|
||||
std::vector<struct s_attendance_period> attendance_periods;
|
||||
|
||||
#define MOTD_LINE_SIZE 128
|
||||
static char motd_text[MOTD_LINE_SIZE][CHAT_SIZE_MAX]; // Message of the day buffer [Valaris]
|
||||
|
||||
@ -11724,6 +11746,10 @@ void pc_damage_log_clear(struct map_session_data *sd, int id)
|
||||
void pc_scdata_received(struct map_session_data *sd) {
|
||||
pc_inventory_rentals(sd); // Needed here to remove rentals that have Status Changes after chrif_load_scdata has finished
|
||||
|
||||
if( pc_has_permission( sd, PC_PERM_ATTENDANCE ) && pc_attendance_enabled() && !pc_attendance_rewarded_today( sd ) ){
|
||||
clif_ui_open( sd, OUT_UI_ATTENDANCE, pc_attendance_counter( sd ) );
|
||||
}
|
||||
|
||||
sd->state.pc_loaded = true;
|
||||
|
||||
if (sd->state.connect_new == 0 && sd->fd) { // Character already loaded map! Gotta trigger LoadEndAck manually.
|
||||
@ -12531,6 +12557,260 @@ void pc_set_costume_view(struct map_session_data *sd) {
|
||||
clif_changelook(&sd->bl, LOOK_ROBE, sd->status.robe);
|
||||
}
|
||||
|
||||
struct s_attendance_period* pc_attendance_period(){
|
||||
uint32 date = date_get(DT_YYYYMMDD);
|
||||
|
||||
for( struct s_attendance_period& period : attendance_periods ){
|
||||
if( period.start <= date && period.end >= date ){
|
||||
return .
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool pc_attendance_enabled(){
|
||||
// Check if the attendance feature is disabled
|
||||
if( !battle_config.feature_attendance ){
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if there is a running attendance period
|
||||
return pc_attendance_period() != nullptr;
|
||||
}
|
||||
|
||||
static inline bool pc_attendance_rewarded_today( struct map_session_data* sd ){
|
||||
return pc_readreg2( sd, ATTENDANCE_DATE_VAR ) >= date_get(DT_YYYYMMDD);
|
||||
}
|
||||
|
||||
int32 pc_attendance_counter( struct map_session_data* sd ){
|
||||
struct s_attendance_period* period = pc_attendance_period();
|
||||
|
||||
// No running attendance period
|
||||
if( period == nullptr ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the counter for the current period
|
||||
int counter = pc_readreg2( sd, ATTENDANCE_COUNT_VAR );
|
||||
|
||||
// Check if we have a remaining counter from a previous period
|
||||
if( counter > 0 && pc_readreg2( sd, ATTENDANCE_DATE_VAR ) < period->start ){
|
||||
// Reset the counter to zero
|
||||
pc_setreg2( sd, ATTENDANCE_COUNT_VAR, 0 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 10 * counter + ( ( pc_attendance_rewarded_today(sd) ) ? 1 : 0 );
|
||||
}
|
||||
|
||||
void pc_attendance_claim_reward( struct map_session_data* sd ){
|
||||
// If the user's group does not have the permission
|
||||
if( !pc_has_permission( sd, PC_PERM_ATTENDANCE ) ){
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the attendance feature is disabled
|
||||
if( !pc_attendance_enabled() ){
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the user already got his reward today
|
||||
if( pc_attendance_rewarded_today( sd ) ){
|
||||
return;
|
||||
}
|
||||
|
||||
int32 attendance_counter = pc_readreg2( sd, ATTENDANCE_COUNT_VAR );
|
||||
|
||||
attendance_counter += 1;
|
||||
|
||||
struct s_attendance_period* period = pc_attendance_period();
|
||||
|
||||
if( period == nullptr ){
|
||||
return;
|
||||
}
|
||||
|
||||
if( period->rewards.size() < attendance_counter ){
|
||||
return;
|
||||
}
|
||||
|
||||
pc_setreg2( sd, ATTENDANCE_DATE_VAR, date_get(DT_YYYYMMDD) );
|
||||
pc_setreg2( sd, ATTENDANCE_COUNT_VAR, attendance_counter );
|
||||
|
||||
if( save_settings&CHARSAVE_ATTENDANCE )
|
||||
chrif_save(sd, CSAVE_NORMAL);
|
||||
|
||||
struct s_attendance_reward& reward = period->rewards.at( attendance_counter - 1 );
|
||||
|
||||
struct mail_message msg;
|
||||
|
||||
memset( &msg, 0, sizeof( struct mail_message ) );
|
||||
|
||||
msg.dest_id = sd->status.char_id;
|
||||
safestrncpy( msg.send_name, msg_txt( sd, 788 ), NAME_LENGTH );
|
||||
safesnprintf( msg.title, MAIL_TITLE_LENGTH, msg_txt( sd, 789 ), attendance_counter );
|
||||
safesnprintf( msg.body, MAIL_BODY_LENGTH, msg_txt( sd, 790 ), attendance_counter );
|
||||
|
||||
msg.item[0].nameid = reward.item_id;
|
||||
msg.item[0].amount = reward.amount;
|
||||
msg.item[0].identify = 1;
|
||||
|
||||
msg.status = MAIL_NEW;
|
||||
msg.type = MAIL_INBOX_NORMAL;
|
||||
msg.timestamp = time(NULL);
|
||||
|
||||
intif_Mail_send(0, &msg);
|
||||
|
||||
clif_attendence_response( sd, attendance_counter );
|
||||
}
|
||||
|
||||
void pc_attendance_load( std::string path ){
|
||||
YAML::Node root;
|
||||
|
||||
try{
|
||||
root = YAML::LoadFile( path );
|
||||
}catch( ... ){
|
||||
ShowError( "pc_attendance_load: Failed to read attendance configuration file \"%s\".\n", path.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
if( root["Attendance"] ){
|
||||
YAML::Node attendance = root["Attendance"];
|
||||
|
||||
for( const auto &periodNode : attendance ){
|
||||
if( !periodNode["Start"].IsDefined() ){
|
||||
ShowError( "pc_attendance_load: Missing \"Start\" for period in line %d.\n", periodNode.Mark().line );
|
||||
continue;
|
||||
}
|
||||
|
||||
YAML::Node startNode = periodNode["Start"];
|
||||
|
||||
if( !periodNode["End"].IsDefined() ){
|
||||
ShowError( "pc_attendance_load: Missing \"End\" for period in line %d.\n", periodNode.Mark().line );
|
||||
continue;
|
||||
}
|
||||
|
||||
YAML::Node endNode = periodNode["End"];
|
||||
|
||||
if( !periodNode["Rewards"].IsDefined() ){
|
||||
ShowError( "pc_attendance_load: Missing \"Rewards\" for period in line %d.\n", periodNode.Mark().line );
|
||||
continue;
|
||||
}
|
||||
|
||||
YAML::Node rewardsNode = periodNode["Rewards"];
|
||||
|
||||
uint32 start = startNode.as<uint32>();
|
||||
uint32 end = endNode.as<uint32>();
|
||||
|
||||
// If the period is outdated already, we do not even bother parsing
|
||||
if( end < date_get( DT_YYYYMMDD ) ){
|
||||
continue;
|
||||
}
|
||||
|
||||
// Collision detection
|
||||
bool collision = false;
|
||||
|
||||
for( struct s_attendance_period& period : attendance_periods ){
|
||||
// Check if start is inside another period
|
||||
if( period.start <= start && start <= period.end ){
|
||||
ShowError( "pc_attendance_load: period start %u intersects with period %u-%u.\n", start, period.start, period.end );
|
||||
collision = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if end is inside another period
|
||||
if( period.start <= end && end <= period.end ){
|
||||
ShowError( "pc_attendance_load: period end %u intersects with period %u-%u.\n", start, period.start, period.end );
|
||||
collision = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( collision ){
|
||||
continue;
|
||||
}
|
||||
|
||||
struct s_attendance_period period;
|
||||
|
||||
period.start = start;
|
||||
period.end = end;
|
||||
|
||||
for( const auto& rewardNode : rewardsNode ){
|
||||
if( !rewardNode["Day"].IsDefined() ){
|
||||
ShowError( "pc_attendance_load: No day defined for node in line %d.\n", rewardNode.Mark().line );
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 day = rewardNode["Day"].as<uint32>();
|
||||
|
||||
if( !rewardNode["ItemId"].IsDefined() ){
|
||||
ShowError( "pc_attendance_load: No reward defined for day %d.\n", day );
|
||||
continue;
|
||||
}
|
||||
|
||||
YAML::Node itemNode = rewardNode["ItemId"];
|
||||
|
||||
uint16 item_id = itemNode.as<uint16>();
|
||||
|
||||
if( item_id == 0 || !itemdb_exists( item_id ) ){
|
||||
ShowError( "pc_attendance_load: Unknown item ID %hu for day %d.\n", item_id, day );
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16 amount;
|
||||
|
||||
if( rewardNode["Amount"] ){
|
||||
amount = rewardNode["Amount"].as<uint16>();
|
||||
|
||||
if( amount == 0 ){
|
||||
ShowError( "pc_attendance_load: Invalid reward count %hu for day %d. Defaulting to 1...\n", amount, day );
|
||||
amount = 1;
|
||||
}else if( amount > MAX_AMOUNT ){
|
||||
ShowError( "pc_attendance_load: Reward count %hu above maximum %hu for day %d. Defaulting to %hu...\n", amount, MAX_AMOUNT, day, MAX_AMOUNT );
|
||||
amount = MAX_AMOUNT;
|
||||
}
|
||||
}else{
|
||||
amount = 1;
|
||||
}
|
||||
|
||||
struct s_attendance_reward* reward = &period.rewards[day - 1];
|
||||
|
||||
reward->item_id = item_id;
|
||||
reward->amount = amount;
|
||||
}
|
||||
|
||||
bool missing_day = false;
|
||||
|
||||
for( int day = 0; day < period.rewards.size(); day++ ){
|
||||
if( !util::map_exists( period.rewards, day ) ){
|
||||
ShowError( "pc_attendance_load: Reward for day %d is missing.\n", day + 1 );
|
||||
missing_day = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( missing_day ){
|
||||
continue;
|
||||
}
|
||||
|
||||
attendance_periods.push_back( period );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pc_read_attendance(){
|
||||
char path[1024];
|
||||
|
||||
sprintf( path, "%s/%sattendance.yml", db_path, DBPATH );
|
||||
|
||||
pc_attendance_load( path );
|
||||
|
||||
sprintf( path, "%s/%s/attendance.yml", db_path, DBIMPORT );
|
||||
|
||||
pc_attendance_load( path );
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* pc Init/Terminate
|
||||
*------------------------------------------*/
|
||||
@ -12542,6 +12822,8 @@ void do_final_pc(void) {
|
||||
ers_destroy(pc_itemgrouphealrate_ers);
|
||||
ers_destroy(num_reg_ers);
|
||||
ers_destroy(str_reg_ers);
|
||||
|
||||
attendance_periods.clear();
|
||||
}
|
||||
|
||||
void do_init_pc(void) {
|
||||
@ -12550,6 +12832,7 @@ void do_init_pc(void) {
|
||||
|
||||
pc_readdb();
|
||||
pc_read_motd(); // Read MOTD [Valaris]
|
||||
pc_read_attendance();
|
||||
|
||||
add_timer_func_list(pc_invincible_timer, "pc_invincible_timer");
|
||||
add_timer_func_list(pc_eventtimer, "pc_eventtimer");
|
||||
|
@ -47,6 +47,8 @@ enum sc_type : int16;
|
||||
#define JOBCHANGE3RD_VAR "jobchange_level_3rd"
|
||||
#define TKMISSIONID_VAR "TK_MISSION_ID"
|
||||
#define TKMISSIONCOUNT_VAR "TK_MISSION_COUNT"
|
||||
#define ATTENDANCE_DATE_VAR "#AttendanceDate"
|
||||
#define ATTENDANCE_COUNT_VAR "#AttendanceCounter"
|
||||
|
||||
//Update this max as necessary. 55 is the value needed for Super Baby currently
|
||||
//Raised to 85 since Expanded Super Baby needs it.
|
||||
@ -1338,4 +1340,8 @@ bool pc_job_can_entermap(enum e_job jobid, int m, int group_lv);
|
||||
int pc_level_penalty_mod(int level_diff, uint32 mob_class, enum e_mode mode, int type);
|
||||
#endif
|
||||
|
||||
bool pc_attendance_enabled();
|
||||
int32 pc_attendance_counter( struct map_session_data* sd );
|
||||
void pc_attendance_claim_reward( struct map_session_data* sd );
|
||||
|
||||
#endif /* _PC_HPP_ */
|
||||
|
@ -51,6 +51,7 @@ enum e_pc_permission : uint32 {
|
||||
PC_PERM_ENABLE_COMMAND = 0x01000000,
|
||||
PC_PERM_BYPASS_STAT_ONCLONE = 0x02000000,
|
||||
PC_PERM_BYPASS_MAX_STAT = 0x04000000,
|
||||
PC_PERM_ATTENDANCE = 0x08000000,
|
||||
//.. add other here
|
||||
PC_PERM_ALLPERMISSION = 0xFFFFFFFF,
|
||||
};
|
||||
@ -86,6 +87,7 @@ static const struct s_pcg_permission_name {
|
||||
{ "command_enable",PC_PERM_ENABLE_COMMAND },
|
||||
{ "bypass_stat_onclone",PC_PERM_BYPASS_STAT_ONCLONE },
|
||||
{ "bypass_max_stat",PC_PERM_BYPASS_MAX_STAT },
|
||||
{ "attendance",PC_PERM_ATTENDANCE },
|
||||
{ "all_permission", PC_PERM_ALLPERMISSION },
|
||||
};
|
||||
|
||||
|
@ -4451,6 +4451,7 @@
|
||||
export_constant(DT_MONTH);
|
||||
export_constant(DT_YEAR);
|
||||
export_constant(DT_DAYOFYEAR);
|
||||
export_constant(DT_YYYYMMDD);
|
||||
|
||||
/* instance info */
|
||||
export_constant(IIT_ID);
|
||||
@ -4940,7 +4941,7 @@
|
||||
export_constant(IG_COSTAMA_EGG29);
|
||||
export_constant(IG_INK_BALL);
|
||||
export_constant(IG_SOMETHING_CANDY_HOLDER);
|
||||
export_constant(IG_MYSTERIOUS_EGG);
|
||||
export_constant(IG_SHINING_EGG);
|
||||
export_constant(IG_AGUST_LUCKY_SCROLL);
|
||||
export_constant(IG_ELEMENT);
|
||||
export_constant(IG_POISON);
|
||||
|
Loading…
x
Reference in New Issue
Block a user