Refactored achievements to utilize C++ features (#2607)
* Refactored achievements to utilize C++ features * Cleaned up the YAML parser. * Moved achievements from DBMap to an unordered_map. * Moved achievement targets from DBMap to a vector. * Changed all struct arrays into vectors. * Changed all char arrays to strings. * Changed all int arrays to std::arrays. * Removed achievement_dummy as it's no longer needed. * Achievements now use smart pointer to ensure proper construction and deconstruction of objects. Thanks to @lighta!
This commit is contained in:
parent
ca1b980ede
commit
1c66035761
@ -967,63 +967,63 @@ Achievements:
|
||||
Name: "Prontera Contribution"
|
||||
Map: "prontera"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127002
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Geffen Contribution"
|
||||
Map: "geffen"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127003
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Morocc Contribution"
|
||||
Map: "morocc"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127004
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Payon Contribution"
|
||||
Map: "payon"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127005
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Yuno Contribution"
|
||||
Map: "yuno"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127006
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Lighthalzen Contribution"
|
||||
Map: "lighthalzen"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127007
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Einbroch Contribution"
|
||||
Map: "einbroch"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127008
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Rachel Contribution"
|
||||
Map: "rachel"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127009
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Veins Contribution"
|
||||
Map: "veins"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 128000
|
||||
Group: "AG_BATTLE"
|
||||
@ -2046,35 +2046,35 @@ Achievements:
|
||||
Name: "Activating the market economy (1)"
|
||||
Condition: " ARG0 >= 10000 "
|
||||
Target:
|
||||
Count: 10000
|
||||
- Count: 10000
|
||||
Score: 10
|
||||
- ID: 220010
|
||||
Group: "AG_SPEND_ZENY"
|
||||
Name: "Activating the market economy (2)"
|
||||
Condition: " ARG0 >= 100000 "
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 15
|
||||
- ID: 220011
|
||||
Group: "AG_SPEND_ZENY"
|
||||
Name: "Activating the market economy (3)"
|
||||
Condition: " ARG0 >= 500000 "
|
||||
Target:
|
||||
Count: 500000
|
||||
- Count: 500000
|
||||
Score: 20
|
||||
- ID: 220012
|
||||
Group: "AG_SPEND_ZENY"
|
||||
Name: "Activating the market economy (4)"
|
||||
Condition: " ARG0 >= 1000000 "
|
||||
Target:
|
||||
Count: 1000000
|
||||
- Count: 1000000
|
||||
Score: 30
|
||||
- ID: 220013
|
||||
Group: "AG_SPEND_ZENY"
|
||||
Name: "Activating the market economy (5)"
|
||||
Condition: " ARG0 >= 5000000 "
|
||||
Target:
|
||||
Count: 5000000
|
||||
- Count: 5000000
|
||||
Score: 50
|
||||
- ID: 220014
|
||||
Group: "AG_ENCHANT_SUCCESS"
|
||||
|
@ -967,63 +967,63 @@ Achievements:
|
||||
Name: "Prontera Contribution"
|
||||
Map: "prontera"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127002
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Geffen Contribution"
|
||||
Map: "geffen"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127003
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Morocc Contribution"
|
||||
Map: "morocc"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127004
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Payon Contribution"
|
||||
Map: "payon"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127005
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Yuno Contribution"
|
||||
Map: "yuno"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127006
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Lighthalzen Contribution"
|
||||
Map: "lighthalzen"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127007
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Einbroch Contribution"
|
||||
Map: "einbroch"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127008
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Rachel Contribution"
|
||||
Map: "rachel"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 127009
|
||||
Group: "AG_CHATTING"
|
||||
Name: "Veins Contribution"
|
||||
Map: "veins"
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 10
|
||||
- ID: 128000
|
||||
Group: "AG_BATTLE"
|
||||
@ -2046,35 +2046,35 @@ Achievements:
|
||||
Name: "Activating the market economy (1)"
|
||||
Condition: " ARG0 >= 10000 "
|
||||
Target:
|
||||
Count: 10000
|
||||
- Count: 10000
|
||||
Score: 10
|
||||
- ID: 220010
|
||||
Group: "AG_SPEND_ZENY"
|
||||
Name: "Activating the market economy (2)"
|
||||
Condition: " ARG0 >= 100000 "
|
||||
Target:
|
||||
Count: 100000
|
||||
- Count: 100000
|
||||
Score: 15
|
||||
- ID: 220011
|
||||
Group: "AG_SPEND_ZENY"
|
||||
Name: "Activating the market economy (3)"
|
||||
Condition: " ARG0 >= 500000 "
|
||||
Target:
|
||||
Count: 500000
|
||||
- Count: 500000
|
||||
Score: 20
|
||||
- ID: 220012
|
||||
Group: "AG_SPEND_ZENY"
|
||||
Name: "Activating the market economy (4)"
|
||||
Condition: " ARG0 >= 1000000 "
|
||||
Target:
|
||||
Count: 1000000
|
||||
- Count: 1000000
|
||||
Score: 30
|
||||
- ID: 220013
|
||||
Group: "AG_SPEND_ZENY"
|
||||
Name: "Activating the market economy (5)"
|
||||
Condition: " ARG0 >= 5000000 "
|
||||
Target:
|
||||
Count: 5000000
|
||||
- Count: 5000000
|
||||
Score: 50
|
||||
- ID: 220014
|
||||
Group: "AG_ENCHANT_SUCCESS"
|
||||
|
@ -64,7 +64,7 @@ Example 2:
|
||||
// IE: In the achievement_list.lub file, UI_Type 0 is displayed as non-incremental while 1 shows a progress bar of completion for the achievement.
|
||||
Condition: " ARG0 >= 100 "
|
||||
Target:
|
||||
Count: 100
|
||||
- Count: 100
|
||||
|
||||
---------------------------------------
|
||||
|
||||
|
@ -143,8 +143,8 @@
|
||||
|
||||
//Achievement System
|
||||
#define MAX_ACHIEVEMENT_RANK 20 /// Maximum achievement level
|
||||
#define MAX_ACHIEVEMENT_OBJECTIVES 10 /// Maximum different objectives in achievement_db.conf
|
||||
#define MAX_ACHIEVEMENT_DEPENDENTS 20 /// Maximum different dependents in achievement_db.conf
|
||||
#define MAX_ACHIEVEMENT_OBJECTIVES 10 /// Maximum different objectives in achievement_db.yml
|
||||
#define MAX_ACHIEVEMENT_DEPENDENTS 20 /// Maximum different dependents in achievement_db.yml
|
||||
#define ACHIEVEMENT_NAME_LENGTH 50 /// Max Achievement Name length
|
||||
|
||||
enum item_types {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,9 +4,18 @@
|
||||
#ifndef _ACHIEVEMENT_HPP_
|
||||
#define _ACHIEVEMENT_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "../common/mmo.h"
|
||||
#include "../common/db.h"
|
||||
|
||||
struct map_session_data;
|
||||
struct block_list;
|
||||
|
||||
enum e_achievement_group {
|
||||
AG_NONE = 0,
|
||||
AG_ADD_FRIEND,
|
||||
@ -54,51 +63,43 @@ enum e_achievement_info {
|
||||
ACHIEVEINFO_MAX,
|
||||
};
|
||||
|
||||
struct achievement_mob {
|
||||
int mod_id;
|
||||
};
|
||||
|
||||
struct achievement_target {
|
||||
int mob;
|
||||
int count;
|
||||
};
|
||||
|
||||
struct achievement_dependent {
|
||||
int achievement_id;
|
||||
};
|
||||
|
||||
struct av_condition {
|
||||
int op;
|
||||
struct av_condition *left;
|
||||
struct av_condition *right;
|
||||
std::shared_ptr<struct av_condition> left;
|
||||
std::shared_ptr<struct av_condition> right;
|
||||
long long value;
|
||||
|
||||
av_condition() : op(0), left(nullptr), right(nullptr), value(0) {}
|
||||
};
|
||||
|
||||
struct achievement_db {
|
||||
struct s_achievement_db {
|
||||
int achievement_id;
|
||||
char name[ACHIEVEMENT_NAME_LENGTH];
|
||||
std::string name;
|
||||
enum e_achievement_group group;
|
||||
uint8 target_count;
|
||||
struct achievement_target *targets;
|
||||
uint8 dependent_count;
|
||||
struct achievement_dependent *dependents;
|
||||
struct av_condition *condition;
|
||||
std::vector <achievement_target> targets;
|
||||
std::vector <int> dependent_ids;
|
||||
std::shared_ptr<struct av_condition> condition;
|
||||
int16 mapindex;
|
||||
struct ach_reward {
|
||||
unsigned short nameid, amount;
|
||||
struct script_code *script;
|
||||
int title_id;
|
||||
ach_reward();
|
||||
~ach_reward();
|
||||
} rewards;
|
||||
int score;
|
||||
int has_dependent; // Used for quick updating of achievements that depend on others - this is their ID
|
||||
|
||||
s_achievement_db();
|
||||
};
|
||||
|
||||
struct map_session_data;
|
||||
struct block_list;
|
||||
|
||||
extern struct achievement_db achievement_dummy; ///< Dummy entry for invalid achievement lookups
|
||||
|
||||
struct achievement_db *achievement_search(int achievement_id);
|
||||
bool achievement_exists(int achievement_id);
|
||||
std::shared_ptr<s_achievement_db>& achievement_get(int achievement_id);
|
||||
bool achievement_mobexists(int mob_id);
|
||||
void achievement_get_reward(struct map_session_data *sd, int achievement_id, time_t rewarded);
|
||||
struct achievement *achievement_add(struct map_session_data *sd, int achievement_id);
|
||||
@ -117,9 +118,9 @@ void do_init_achievement(void);
|
||||
void do_final_achievement(void);
|
||||
|
||||
// Parser
|
||||
const char *av_parse_subexpr(const char *p,int limit, struct av_condition *parent);
|
||||
const char *av_parse_simpleexpr(const char *p, struct av_condition *parent);
|
||||
long long achievement_check_condition(struct av_condition *condition, struct map_session_data *sd, int *count);
|
||||
void achievement_script_free(struct av_condition *condition);
|
||||
const char *av_parse_subexpr(const char *p,int limit, std::shared_ptr<struct av_condition> parent);
|
||||
const char *av_parse_simpleexpr(const char *p, std::shared_ptr<struct av_condition> parent);
|
||||
long long achievement_check_condition(std::shared_ptr<struct av_condition> condition, struct map_session_data *sd, const int *count);
|
||||
void achievement_script_free(std::shared_ptr<struct av_condition> condition);
|
||||
|
||||
#endif /* _ACHIEVEMENT_HPP_ */
|
||||
|
@ -19020,7 +19020,7 @@ void clif_change_title_ack(struct map_session_data *sd, unsigned char result, un
|
||||
*/
|
||||
void clif_parse_change_title(int fd, struct map_session_data *sd)
|
||||
{
|
||||
int title_id, i;
|
||||
int title_id;
|
||||
|
||||
nullpo_retv(sd);
|
||||
|
||||
@ -19032,8 +19032,7 @@ void clif_parse_change_title(int fd, struct map_session_data *sd)
|
||||
}else if( title_id <= 0 ){
|
||||
sd->status.title_id = 0;
|
||||
}else{
|
||||
ARR_FIND(0, sd->titleCount, i, sd->titles[i] == title_id);
|
||||
if( i == sd->titleCount ){
|
||||
if (std::find(sd->titles.begin(), sd->titles.end(), title_id) != sd->titles.end()) {
|
||||
clif_change_title_ack(sd, 1, title_id);
|
||||
return;
|
||||
}
|
||||
|
@ -2130,13 +2130,14 @@ void intif_parse_achievements(int fd)
|
||||
CREATE(sd->achievement_data.achievements, struct achievement, num_received);
|
||||
|
||||
for (i = 0; i < num_received; i++) {
|
||||
struct achievement_db *adb = achievement_search(received[i].achievement_id);
|
||||
|
||||
if (!adb) {
|
||||
if (!achievement_exists(received[i].achievement_id)) {
|
||||
ShowError("intif_parse_achievementlog: Achievement %d not found in DB.\n", received[i].achievement_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto &adb = achievement_get(received[i].achievement_id);
|
||||
|
||||
received[i].score = adb->score;
|
||||
|
||||
if (received[i].completed == 0) // Insert at the beginning
|
||||
@ -2220,7 +2221,7 @@ void intif_parse_achievementreward(int fd){
|
||||
/**
|
||||
* Request the achievement rewards from the inter server.
|
||||
*/
|
||||
int intif_achievement_reward(struct map_session_data *sd, struct achievement_db *adb){
|
||||
int intif_achievement_reward(struct map_session_data *sd, struct s_achievement_db *adb){
|
||||
if( CheckForCharServer() ){
|
||||
return 0;
|
||||
}
|
||||
@ -2232,7 +2233,7 @@ int intif_achievement_reward(struct map_session_data *sd, struct achievement_db
|
||||
WFIFOW(inter_fd, 10) = adb->rewards.nameid;
|
||||
WFIFOL(inter_fd, 12) = adb->rewards.amount;
|
||||
safestrncpy(WFIFOCP(inter_fd, 16), sd->status.name, NAME_LENGTH);
|
||||
safestrncpy(WFIFOCP(inter_fd, 16+NAME_LENGTH), adb->name, ACHIEVEMENT_NAME_LENGTH);
|
||||
safestrncpy(WFIFOCP(inter_fd, 16+NAME_LENGTH), adb->name.c_str(), ACHIEVEMENT_NAME_LENGTH);
|
||||
WFIFOSET(inter_fd, 16+NAME_LENGTH+ACHIEVEMENT_NAME_LENGTH);
|
||||
|
||||
return 1;
|
||||
|
@ -16,7 +16,7 @@ struct s_mercenary;
|
||||
struct s_elemental;
|
||||
struct mail_message;
|
||||
struct auction_data;
|
||||
struct achievement_db;
|
||||
struct s_achievement_db;
|
||||
struct map_session_data;
|
||||
|
||||
int intif_parse(int fd);
|
||||
@ -119,7 +119,7 @@ int intif_clan_member_left( int clan_id );
|
||||
// ACHIEVEMENT SYSTEM
|
||||
void intif_request_achievements(uint32 char_id);
|
||||
int intif_achievement_save(struct map_session_data *sd);
|
||||
int intif_achievement_reward(struct map_session_data *sd, struct achievement_db *adb);
|
||||
int intif_achievement_reward(struct map_session_data *sd, struct s_achievement_db *adb);
|
||||
|
||||
int intif_request_accinfo(int u_fd, int aid, int group_lv, char* query, char type);
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
#ifndef _PC_HPP_
|
||||
#define _PC_HPP_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus
|
||||
#include "../common/strlib.h"// StringBuf
|
||||
|
||||
@ -612,8 +614,7 @@ struct map_session_data {
|
||||
} achievement_data;
|
||||
|
||||
// Title system
|
||||
int *titles;
|
||||
uint8 titleCount;
|
||||
std::vector<int> titles;
|
||||
|
||||
/* ShowEvent Data Cache flags from map */
|
||||
bool *qi_display;
|
||||
|
@ -23374,7 +23374,7 @@ BUILDIN_FUNC(achievementadd) {
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
}
|
||||
|
||||
if (achievement_search(achievement_id) == &achievement_dummy) {
|
||||
if (achievement_exists(achievement_id) == false) {
|
||||
ShowWarning("buildin_achievementadd: Achievement '%d' doesn't exist.\n", achievement_id);
|
||||
script_pushint(st, false);
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
@ -23411,7 +23411,7 @@ BUILDIN_FUNC(achievementremove) {
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
}
|
||||
|
||||
if (achievement_search(achievement_id) == &achievement_dummy) {
|
||||
if (achievement_exists(achievement_id) == false) {
|
||||
ShowWarning("buildin_achievementremove: Achievement '%d' doesn't exist.\n", achievement_id);
|
||||
script_pushint(st, false);
|
||||
return SCRIPT_CMD_SUCCESS;
|
||||
@ -23447,7 +23447,7 @@ BUILDIN_FUNC(achievementinfo) {
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
}
|
||||
|
||||
if (achievement_search(achievement_id) == &achievement_dummy) {
|
||||
if (achievement_exists(achievement_id) == false) {
|
||||
ShowWarning("buildin_achievementinfo: Achievement '%d' doesn't exist.\n", achievement_id);
|
||||
script_pushint(st, false);
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
@ -23481,7 +23481,7 @@ BUILDIN_FUNC(achievementcomplete) {
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
}
|
||||
|
||||
if (achievement_search(achievement_id) == &achievement_dummy) {
|
||||
if (achievement_exists(achievement_id) == false) {
|
||||
ShowWarning("buildin_achievementcomplete: Achievement '%d' doesn't exist.\n", achievement_id);
|
||||
script_pushint(st, false);
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
@ -23518,7 +23518,7 @@ BUILDIN_FUNC(achievementexists) {
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
}
|
||||
|
||||
if (achievement_search(achievement_id) == &achievement_dummy) {
|
||||
if (achievement_exists(achievement_id) == false) {
|
||||
ShowWarning("buildin_achievementexists: Achievement '%d' doesn't exist.\n", achievement_id);
|
||||
script_pushint(st, false);
|
||||
return SCRIPT_CMD_SUCCESS;
|
||||
@ -23557,7 +23557,7 @@ BUILDIN_FUNC(achievementupdate) {
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
}
|
||||
|
||||
if (achievement_search(achievement_id) == &achievement_dummy) {
|
||||
if (achievement_exists(achievement_id) == false) {
|
||||
ShowWarning("buildin_achievementupdate: Achievement '%d' doesn't exist.\n", achievement_id);
|
||||
script_pushint(st, false);
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
|
Loading…
x
Reference in New Issue
Block a user