From ae74eb840480d358c8250d35bd9d28c097794e28 Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Thu, 18 Aug 2022 17:50:40 +0200 Subject: [PATCH] Initial release of reputation UI (#7184) Co-authored-by: Aleos --- db/import-tmpl/reputation.yml | 34 ++++++++++++++ db/re/reputation.yml | 56 ++++++++++++++++++++++ db/reputation.yml | 40 ++++++++++++++++ doc/script_commands.txt | 14 ++++++ src/map/clif.cpp | 43 +++++++++++++++++ src/map/clif.hpp | 4 ++ src/map/map-server.vcxproj | 1 + src/map/packets.hpp | 13 ++++++ src/map/pc.cpp | 87 +++++++++++++++++++++++++++++++++++ src/map/pc.hpp | 20 ++++++++ src/map/script.cpp | 54 ++++++++++++++++++++++ 11 files changed, 366 insertions(+) create mode 100644 db/import-tmpl/reputation.yml create mode 100644 db/re/reputation.yml create mode 100644 db/reputation.yml diff --git a/db/import-tmpl/reputation.yml b/db/import-tmpl/reputation.yml new file mode 100644 index 0000000000..6fe243b69c --- /dev/null +++ b/db/import-tmpl/reputation.yml @@ -0,0 +1,34 @@ +# This file is a part of rAthena. +# Copyright(C) 2022 rAthena Development Team +# https://rathena.org - https://github.com/rathena +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +########################################################################### +# Reputation Database +########################################################################### +# +# Reputation Settings +# +########################################################################### +# - Id Client side index. +# Name Name of the reputation type. +# Variable Name of the variable that will store the reputation. (Default: RepPoints) +# Minimum Minimum amount of points. (Default: INT64_MIN) +# Maximum Maximum amount of points. (Default: INT64_MAX) +########################################################################### + +Header: + Type: REPUTATION_DB + Version: 1 diff --git a/db/re/reputation.yml b/db/re/reputation.yml new file mode 100644 index 0000000000..0ebb9f3602 --- /dev/null +++ b/db/re/reputation.yml @@ -0,0 +1,56 @@ +# This file is a part of rAthena. +# Copyright(C) 2022 rAthena Development Team +# https://rathena.org - https://github.com/rathena +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +########################################################################### +# Reputation Database +########################################################################### +# +# Reputation Settings +# +########################################################################### +# - Id Client side index. +# Name Name of the reputation type. +# Variable Name of the variable that will store the reputation. (Default: RepPoints) +# Minimum Minimum amount of points. (Default: INT64_MIN) +# Maximum Maximum amount of points. (Default: INT64_MAX) +########################################################################### + +Header: + Type: REPUTATION_DB + Version: 1 + +Body: + - Id: 1 + Name: Orc Village + Variable: RepPointsOrc + Minimum: -3000 + Maximum: 3000 + - Id: 2 + Name: Goblin Village + Variable: RepPointsGoblin + Minimum: -3000 + Maximum: 3000 + - Id: 3 + Name: Grey Wolf Village + Variable: RepPointsWolf + Minimum: -5000 + Maximum: 5000 + - Id: 4 + Name: Isgard + Variable: RepPointsIsgard + Minimum: -3000 + Maximum: 3000 diff --git a/db/reputation.yml b/db/reputation.yml new file mode 100644 index 0000000000..ff740ef13f --- /dev/null +++ b/db/reputation.yml @@ -0,0 +1,40 @@ +# This file is a part of rAthena. +# Copyright(C) 2022 rAthena Development Team +# https://rathena.org - https://github.com/rathena +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +########################################################################### +# Reputation Database +########################################################################### +# +# Reputation Settings +# +########################################################################### +# - Id Client side index. +# Name Name of the reputation type. +# Variable Name of the variable that will store the reputation. (Default: RepPoints) +# Minimum Minimum amount of points. (Default: INT64_MIN) +# Maximum Maximum amount of points. (Default: INT64_MAX) +########################################################################### + +Header: + Type: REPUTATION_DB + Version: 1 + +Footer: + Imports: + - Path: db/re/reputation.yml + Mode: Renewal + - Path: db/import/reputation.yml diff --git a/doc/script_commands.txt b/doc/script_commands.txt index af2dcbb6f2..a0a1e12fc0 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -8174,6 +8174,20 @@ Opens the enchantgrade UI for the attached character or the player given by the This command requires packet version 2020-07-24 or newer. +--------------------------------------- + +*set_reputation_points(,{,}) + +Sets the reputation points via for reputation group for the attached player or the given character ID. + is the client side index as stored in the Id field of the reputation.yml database files. + +--------------------------------------- + +*get_reputation_points({,}) + +Gets the reputation points for reputation group for the attached player or the given character ID. + is the client side index as stored in the Id field of the reputation.yml database files. + --------------------------------------- \\ 6,1.- Unit-related commands diff --git a/src/map/clif.cpp b/src/map/clif.cpp index d3b43ae6ff..2bd9fbe300 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -11092,6 +11092,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) } } #endif + clif_reputation_list( *sd ); if (sd->guild && battle_config.guild_notice_changemap == 1){ clif_guild_notice(sd); // Displays after VIP @@ -23803,6 +23804,48 @@ void clif_parse_enchantgrade_close( int fd, struct map_session_data* sd ){ #endif } +void clif_reputation_type( struct map_session_data& sd, int64 type, int64 points ){ +#if PACKETVER_RE_NUM >= 20211103 + struct PACKET_ZC_REPUTE_INFO* p = (struct PACKET_ZC_REPUTE_INFO*)packet_buffer; + + p->packetType = HEADER_ZC_REPUTE_INFO; + p->packetLength = sizeof( struct PACKET_ZC_REPUTE_INFO ) + sizeof( struct PACKET_ZC_REPUTE_INFO_sub ); + p->success = true; + + struct PACKET_ZC_REPUTE_INFO_sub* entry = &p->list[0]; + + entry->type = type; + entry->points = points; + + clif_send( p, p->packetLength, &sd.bl, SELF ); +#endif +} + +void clif_reputation_list( struct map_session_data& sd ){ +#if PACKETVER_RE_NUM >= 20211103 + struct PACKET_ZC_REPUTE_INFO* p = (struct PACKET_ZC_REPUTE_INFO*)packet_buffer; + + p->packetType = HEADER_ZC_REPUTE_INFO; + p->packetLength = sizeof( struct PACKET_ZC_REPUTE_INFO ); + p->success = true; + + size_t index = 0; + for( const auto& entry : reputation_db ){ + std::shared_ptr reputation = entry.second; + + struct PACKET_ZC_REPUTE_INFO_sub* list_entry = &p->list[index]; + + list_entry->type = reputation->id; + list_entry->points = pc_readreg2( &sd, reputation->variable.c_str() ); + + p->packetLength += sizeof( *list_entry ); + index++; + } + + clif_send( p, p->packetLength, &sd.bl, SELF ); +#endif +} + /*========================================== * Main client packet processing function *------------------------------------------*/ diff --git a/src/map/clif.hpp b/src/map/clif.hpp index 239e0ed9fd..346f56b570 100644 --- a/src/map/clif.hpp +++ b/src/map/clif.hpp @@ -1200,4 +1200,8 @@ void clif_summon_hp_bar(struct mob_data& md); void clif_laphine_synthesis_open( struct map_session_data *sd, std::shared_ptr synthesis ); void clif_laphine_upgrade_open( struct map_session_data* sd, std::shared_ptr upgrade ); +// Reputation System +void clif_reputation_type( struct map_session_data& sd, int64 type, int64 points ); +void clif_reputation_list( struct map_session_data& sd ); + #endif /* CLIF_HPP */ diff --git a/src/map/map-server.vcxproj b/src/map/map-server.vcxproj index 453f1045aa..75780125a0 100644 --- a/src/map/map-server.vcxproj +++ b/src/map/map-server.vcxproj @@ -356,6 +356,7 @@ + diff --git a/src/map/packets.hpp b/src/map/packets.hpp index 367581cbbf..40af0ad079 100644 --- a/src/map/packets.hpp +++ b/src/map/packets.hpp @@ -246,6 +246,18 @@ struct PACKET_ZC_SUMMON_HP_UPDATE { uint32 Value; } __attribute__((packed)); +struct PACKET_ZC_REPUTE_INFO_sub{ + uint64 type; + int64 points; +} __attribute__((packed)); + +struct PACKET_ZC_REPUTE_INFO{ + int16 packetType; + int16 packetLength; + uint8 success; + struct PACKET_ZC_REPUTE_INFO_sub list[]; +} __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 ) @@ -300,6 +312,7 @@ DEFINE_PACKET_HEADER(ZC_UNCONFIRMED_SPIRITS3, 0xb73) DEFINE_PACKET_HEADER(CZ_UNCONFIRMED_RODEX_RETURN, 0xb98) DEFINE_PACKET_HEADER(ZC_SUMMON_HP_INIT, 0xb6b) DEFINE_PACKET_HEADER(ZC_SUMMON_HP_UPDATE, 0xb6c) +DEFINE_PACKET_HEADER(ZC_REPUTE_INFO, 0x0b8d) const int16 MAX_INVENTORY_ITEM_PACKET_NORMAL = ( ( INT16_MAX - ( sizeof( struct packet_itemlist_normal ) - ( sizeof( struct NORMALITEM_INFO ) * MAX_ITEMLIST) ) ) / sizeof( struct NORMALITEM_INFO ) ); const int16 MAX_INVENTORY_ITEM_PACKET_EQUIP = ( ( INT16_MAX - ( sizeof( struct packet_itemlist_equip ) - ( sizeof( struct EQUIPITEM_INFO ) * MAX_ITEMLIST ) ) ) / sizeof( struct EQUIPITEM_INFO ) ); diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 29b0b0d0e5..11b4ec263a 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -262,6 +262,91 @@ uint64 AttendanceDatabase::parseBodyNode(const ryml::NodeRef& node){ AttendanceDatabase attendance_db; +const std::string ReputationDatabase::getDefaultLocation(){ + return std::string( db_path ) + "/reputation.yml"; +} + +uint64 ReputationDatabase::parseBodyNode( const ryml::NodeRef& node ){ + int64 id; + + if( !this->asInt64( node, "Id", id ) ){ + return 0; + } + + std::shared_ptr reputation = this->find( id ); + bool exists = reputation != nullptr; + + if( !exists ){ + if( !this->nodesExist( node, { "Name", "Variable" } ) ){ + return 0; + } + + reputation = std::make_shared(); + reputation->id = id; + } + + if( this->nodeExists( node, "Name" ) ){ + std::string name; + + if( !this->asString( node, "Name", name ) ){ + return 0; + } + + reputation->name = name; + } + + if( this->nodeExists( node, "Variable" ) ){ + std::string variable; + + if( !this->asString( node, "Variable", variable ) ){ + return 0; + } + + if( variable.length() > 32 ){ + this->invalidWarning( node, "Variable name \"%s\" exceeds maximum length 32.\n", variable.c_str() ); + return 0; + } + + reputation->variable = variable; + } + + if( this->nodeExists( node, "Minimum" ) ){ + int64 minimum; + + if( !this->asInt64( node, "Minimum", minimum ) ){ + return 0; + } + + reputation->minimum = minimum; + }else{ + if( !exists ){ + reputation->minimum = INT64_MIN; + } + } + + if( this->nodeExists( node, "Maximum" ) ){ + int64 maximum; + + if( !this->asInt64( node, "Maximum", maximum ) ){ + return 0; + } + + reputation->maximum = maximum; + }else{ + if( !exists ){ + reputation->maximum = INT64_MIN; + } + } + + if( !exists ){ + this->put( id, reputation ); + } + + return 1; +} + +ReputationDatabase reputation_db; + const std::string PenaltyDatabase::getDefaultLocation(){ return std::string( db_path ) + "/level_penalty.yml"; } @@ -14914,6 +14999,7 @@ void do_final_pc(void) { ers_destroy(str_reg_ers); attendance_db.clear(); + reputation_db.clear(); penalty_db.clear(); } @@ -14924,6 +15010,7 @@ void do_init_pc(void) { pc_readdb(); pc_read_motd(); // Read MOTD [Valaris] attendance_db.load(); + reputation_db.load(); add_timer_func_list(pc_invincible_timer, "pc_invincible_timer"); add_timer_func_list(pc_eventtimer, "pc_eventtimer"); diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 7ecc342527..2de7972149 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -1202,6 +1202,26 @@ public: extern AttendanceDatabase attendance_db; +struct s_reputation{ + int64 id; + std::string name; + std::string variable; + int64 minimum; + int64 maximum; +}; + +class ReputationDatabase : public TypesafeYamlDatabase{ +public: + ReputationDatabase() : TypesafeYamlDatabase( "REPUTATION_DB", 1 ){ + + } + + const std::string getDefaultLocation() override; + uint64 parseBodyNode( const ryml::NodeRef& node ) override; +}; + +extern ReputationDatabase reputation_db; + struct s_statpoint_entry{ uint16 level; uint32 statpoints; diff --git a/src/map/script.cpp b/src/map/script.cpp index 77a6976da7..e66fe67030 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -26038,6 +26038,58 @@ BUILDIN_FUNC( enchantgradeui ){ #endif } +BUILDIN_FUNC(set_reputation_points){ + struct map_session_data* sd; + + if( !script_charid2sd( 4, sd ) ){ + return SCRIPT_CMD_FAILURE; + } + + int64 type = script_getnum64( st, 2 ); + std::shared_ptr reputation = reputation_db.find( type ); + + if( reputation == nullptr ){ + ShowError( "buildin_set_reputation_points: Unknown reputation type %" PRIi64 ".\n", type ); + return SCRIPT_CMD_FAILURE; + } + + int64 points = script_getnum64( st, 3 ); + + points = cap_value( points, reputation->minimum, reputation->maximum ); + + if( !pc_setreg2( sd, reputation->variable.c_str(), points ) ){ + return SCRIPT_CMD_FAILURE; + } + + clif_reputation_type( *sd, type, points ); + + return SCRIPT_CMD_SUCCESS; +} + +BUILDIN_FUNC(get_reputation_points){ + struct map_session_data* sd; + + if( !script_charid2sd( 3, sd ) ){ + return SCRIPT_CMD_FAILURE; + } + + int64 type = script_getnum64( st, 2 ); + std::shared_ptr reputation = reputation_db.find( type ); + + if( reputation == nullptr ){ + ShowError( "buildin_set_reputation_points: Unknown reputation type %" PRIi64 ".\n", type ); + return SCRIPT_CMD_FAILURE; + } + + int64 points = pc_readreg2( sd, reputation->variable.c_str() ); + + points = cap_value( points, reputation->minimum, reputation->maximum ); + + script_pushint( st, points ); + + return SCRIPT_CMD_SUCCESS; +} + #include "../custom/script.inc" // declarations that were supposed to be exported from npc_chat.cpp @@ -26759,6 +26811,8 @@ struct script_function buildin_func[] = { BUILDIN_DEF(getjobexp_ratio, "i??"), BUILDIN_DEF(enchantgradeui, "?" ), + BUILDIN_DEF(set_reputation_points, "ii?"), + BUILDIN_DEF(get_reputation_points, "i?"), #include "../custom/script_def.inc" {NULL,NULL,NULL},