瀏覽代碼

Adds EndOnEnd node to status database (#7313)

* Any status defined under EndOnEnd will be removed when the status becomes inactive.
* Renames End to EndOnStart.
* Removes some hard coded statuses.
* Includes YamlUpgrade Tool update to rename End -> EndOnStart.
Thanks to @Lemongrass3110!
Aleos 2 年之前
父節點
當前提交
8073d4e084
共有 8 個文件被更改,包括 357 次插入297 次删除
  1. 3 2
      db/import-tmpl/status.yml
  2. 127 109
      db/pre-re/status.yml
  3. 119 109
      db/re/status.yml
  4. 3 2
      db/status.yml
  5. 6 2
      doc/status.txt
  6. 51 55
      src/map/status.cpp
  7. 19 18
      src/map/status.hpp
  8. 29 0
      src/tool/yamlupgrade.cpp

+ 3 - 2
db/import-tmpl/status.yml

@@ -35,10 +35,11 @@
 #   MinRate                   Minimum rate after status change reduction (10000 = 100%). (Default: 0)
 #   MinDuration               Minimum duration in milliseconds after status change reduction. (Default: 1)
 #   Fail:                     List of Status Changes that causes the status to fail to activate. (Optional)
-#   End:                      List of Status Changes that will end when the status activates. (Optional)
+#   EndOnStart:               List of Status Changes that will end when the status activates. (Optional)
 #   EndReturn:                List of Status Changes that will end when the status activates and won't give its effect. (Optional)
+#   EndOnEnd:                 List of Status Changes that will end when the status becomes inactive. (Optional)
 ###########################################################################
 
 Header:
   Type: STATUS_DB
-  Version: 2
+  Version: 3

文件差異過大導致無法顯示
+ 127 - 109
db/pre-re/status.yml


文件差異過大導致無法顯示
+ 119 - 109
db/re/status.yml


+ 3 - 2
db/status.yml

@@ -35,13 +35,14 @@
 #   MinRate                   Minimum rate after status change reduction (10000 = 100%). (Default: 0)
 #   MinDuration               Minimum duration in milliseconds after status change reduction. (Default: 1)
 #   Fail:                     List of Status Changes that causes the status to fail to activate. (Optional)
-#   End:                      List of Status Changes that will end when the status activates. (Optional)
+#   EndOnStart:               List of Status Changes that will end when the status activates. (Optional)
 #   EndReturn:                List of Status Changes that will end when the status activates and won't give its effect. (Optional)
+#   EndOnEnd:                 List of Status Changes that will end when the status becomes inactive. (Optional)
 ###########################################################################
 
 Header:
   Type: STATUS_DB
-  Version: 2
+  Version: 3
 
 Footer:
   Imports:

+ 6 - 2
doc/status.txt

@@ -3,7 +3,7 @@
 //===== By: ==================================================
 //= rAthena Dev Team
 //===== Last Updated: ========================================
-//= 20220421
+//= 20221013
 //===== Description: =========================================
 //= Explanation of the status.yml file and structure.
 //============================================================
@@ -266,7 +266,7 @@ Fail: List of status that causes the status to fail to activate.
 
 ---------------------------------------
 
-End: List of status that will end if the status activates.
+EndOnStart: List of status that will end if the status activates.
 
 ---------------------------------------
 
@@ -276,6 +276,10 @@ EndReturn: List of status that will end if the status activates and it won't giv
 
 ---------------------------------------
 
+EndOnEnd: List of status that will end when the status becomes inactive.
+
+---------------------------------------
+
 Notes:
 
 By default, statuses are 'Buff' (those that aren't explicitely given the 'Debuff' flag) which are removable by 'map_quit' in combination with 'battle_config.debuff_on_logout'.

+ 51 - 55
src/map/status.cpp

@@ -988,14 +988,14 @@ std::bitset<SCB_MAX> StatusDatabase::getCalcFlag(sc_type type) {
 }
 
 /**
- * Get SC's END list
+ * Get SC's EndOnStart list
  * @param sc: SC type
  * @return End list
  **/
-std::vector<sc_type> StatusDatabase::getEnd(sc_type type) {
+std::vector<sc_type> StatusDatabase::getEndOnStart(sc_type type) {
 	std::shared_ptr<s_status_change_db> status = status_db.find(type);
 
-	return status ? status->end : std::vector<sc_type> {};
+	return status ? status->endonstart : std::vector<sc_type> {};
 }
 
 /**
@@ -10240,9 +10240,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 	std::vector<sc_type> endlist;
 
 	if (type == SC_BERSERK && val3 == SC__BLOODYLUST) //There is some reasons that using SC_BERSERK first before SC__BLOODYLUST itself on Akinari's fix
-		endlist = status_db.getEnd(SC__BLOODYLUST);
+		endlist = status_db.getEndOnStart(SC__BLOODYLUST);
 	else
-		endlist = scdb->end;
+		endlist = scdb->endonstart;
 
 	// End the SCs from the list
 	if (!endlist.empty()) {
@@ -12513,7 +12513,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			break;
 
 		default:
-			if (calc_flag.none() && scdb->skill_id == 0 && scdb->icon == EFST_BLANK && scdb->opt1 == OPT1_NONE && scdb->opt2 == OPT2_NONE && scdb->state.none() && scdb->flag.none() && scdb->end.empty() && scdb->endreturn.empty() && scdb->fail.empty()) {
+			if (calc_flag.none() && scdb->skill_id == 0 && scdb->icon == EFST_BLANK && scdb->opt1 == OPT1_NONE && scdb->opt2 == OPT2_NONE && scdb->state.none() && scdb->flag.none() && scdb->endonstart.empty() && scdb->endreturn.empty() && scdb->fail.empty() && scdb->endonend.empty()) {
 				// Status change with no calc, no icon, and no skill associated...?
 				ShowWarning("status_change_start: Status %s (%d) is bare. Add the NoWarning flag to suppress this message.\n", script_get_constant_str("SC_", type), type);
 				return 0;
@@ -13072,11 +13072,6 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 						((TBL_MER*)d_bl)->devotion_flag = 0;
 					clif_devotion(d_bl, NULL);
 				}
-
-				status_change_end(bl, SC_AUTOGUARD);
-				status_change_end(bl, SC_DEFENDER);
-				status_change_end(bl, SC_REFLECTSHIELD);
-				status_change_end(bl, SC_ENDURE);
 			}
 			break;
 
@@ -13138,12 +13133,6 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 
 				if((sce->val1&0xFFFF) == CG_MOONLIT)
 					clif_status_change(bl,EFST_MOON,0,0,0,0,0);
-
-#ifdef RENEWAL
-				status_change_end(bl, SC_ENSEMBLEFATIGUE);
-#else
-				status_change_end(bl, SC_LONGING);
-#endif
 			}
 			break;
 		case SC_NOCHAT:
@@ -13371,9 +13360,6 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 				}
 			}
 			break;
-		case SC_TEARGAS:
-			status_change_end(bl,SC_TEARGAS_SOB);
-			break;
 		case SC_SITDOWN_FORCE:
 		case SC_BANANA_BOMB_SITDOWN:
 			if( sd && pc_issit(sd) && pc_setstand(sd, false) )
@@ -13387,25 +13373,6 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 			calc_flag = status_db.getSCB_ALL(); // Required for overlapping
 			break;
 
-		case SC_SUNSTANCE:
-			status_change_end(bl, SC_LIGHTOFSUN);
-			break;
-		case SC_LUNARSTANCE:
-			status_change_end(bl, SC_NEWMOON);
-			status_change_end(bl, SC_LIGHTOFMOON);
-			break;
-		case SC_STARSTANCE:
-			status_change_end(bl, SC_FALLINGSTAR);
-			status_change_end(bl, SC_LIGHTOFSTAR);
-			break;
-		case SC_UNIVERSESTANCE:
-			status_change_end(bl, SC_LIGHTOFSUN);
-			status_change_end(bl, SC_NEWMOON);
-			status_change_end(bl, SC_LIGHTOFMOON);
-			status_change_end(bl, SC_FALLINGSTAR);
-			status_change_end(bl, SC_LIGHTOFSTAR);
-			status_change_end(bl, SC_DIMENSION);
-			break;
 		case SC_GRAVITYCONTROL:
 			status_fix_damage(bl, bl, sce->val2, clif_damage(bl, bl, gettick(), 0, 0, sce->val2, 0, DMG_NORMAL, 0, false), 0);
 			clif_specialeffect(bl, 223, AREA);
@@ -13479,13 +13446,6 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 			///< !CHECKME: Seems on official, there's delay before same target can be vacuumed in same area again [Cydh]
 			sc_start2(bl, bl, SC_VACUUM_EXTREME_POSTDELAY, 100, sce->val1, sce->val2, skill_get_time2(SO_VACUUM_EXTREME,sce->val1));
 			break;
-		case SC_SWORDCLAN:
-		case SC_ARCWANDCLAN:
-		case SC_GOLDENMACECLAN:
-		case SC_CROSSBOWCLAN:
-		case SC_JUMPINGCLAN:
-			status_change_end(bl,SC_CLAN_INFO);
-			break;
 		case SC_DIMENSION1:
 		case SC_DIMENSION2:
 			if (sd)
@@ -13523,9 +13483,6 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 				pc_delservantball( *sd, sd->servantball );
 			}
 			break;
-		case SC_CHARGINGPIERCE:
-			status_change_end(bl, SC_CHARGINGPIERCE_COUNT);
-			break;
 		case SC_ABYSSFORCEWEAPON:
 			if( sd ){
 				pc_delabyssball( *sd, sd->abyssball );
@@ -13533,6 +13490,13 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 			break;
 	}
 
+	// End statuses found in the EndOnEnd list.
+	if (!scdb->endonend.empty()) {
+		for (const auto &it : scdb->endonend) {
+			status_change_end(bl, it);
+		}
+	}
+
 	// Reset the options as needed
 	std::bitset<SCF_MAX> opt_flag = scdb->flag;
 	bool disable_opt_flag = false;
@@ -15651,8 +15615,8 @@ uint64 StatusDatabase::parseBodyNode(const ryml::NodeRef& node) {
 		}
 	}
 
-	if (this->nodeExists(node, "End")) {
-		const ryml::NodeRef& endNode = node["End"];
+	if (this->nodeExists(node, "EndOnStart")) {
+		const ryml::NodeRef& endNode = node["EndOnStart"];
 
 		for (const auto &it : endNode) {
 			std::string end;
@@ -15662,12 +15626,12 @@ uint64 StatusDatabase::parseBodyNode(const ryml::NodeRef& node) {
 			int64 constant;
 
 			if (!script_get_constant(end_constant.c_str(), &constant)) {
-				this->invalidWarning(endNode, "End status %s is invalid.\n", end.c_str());
+				this->invalidWarning(endNode, "EndOnStart status %s is invalid.\n", end.c_str());
 				return 0;
 			}
 
 			if (!this->validateStatus(static_cast<sc_type>(constant))) {
-				this->invalidWarning(endNode, "End status %s is out of bounds.\n", end.c_str());
+				this->invalidWarning(endNode, "EndOnStart status %s is out of bounds.\n", end.c_str());
 				return 0;
 			}
 
@@ -15677,9 +15641,9 @@ uint64 StatusDatabase::parseBodyNode(const ryml::NodeRef& node) {
 				return 0;
 
 			if (active)
-				status->end.push_back(static_cast<sc_type>(constant));
+				status->endonstart.push_back(static_cast<sc_type>(constant));
 			else
-				util::vector_erase_if_exists(status->end, static_cast<sc_type>(constant));
+				util::vector_erase_if_exists(status->endonstart, static_cast<sc_type>(constant));
 		}
 	}
 
@@ -15715,6 +15679,38 @@ uint64 StatusDatabase::parseBodyNode(const ryml::NodeRef& node) {
 		}
 	}
 
+	if (this->nodeExists(node, "EndOnEnd")) {
+		const ryml::NodeRef &endNode = node["EndOnEnd"];
+
+		for (const auto &it : endNode) {
+			std::string end;
+			c4::from_chars(it.key(), &end);
+
+			std::string end_constant = "SC_" + end;
+			int64 constant;
+
+			if (!script_get_constant(end_constant.c_str(), &constant)) {
+				this->invalidWarning(endNode, "EndOnEnd status %s is invalid.\n", end.c_str());
+				return 0;
+			}
+
+			if (!this->validateStatus(static_cast<sc_type>(constant))) {
+				this->invalidWarning(endNode, "EndOnEnd status %s is out of bounds.\n", end.c_str());
+				return 0;
+			}
+
+			bool active;
+
+			if (!this->asBool(endNode, end, active))
+				return 0;
+
+			if (active)
+				status->endonend.push_back(static_cast<sc_type>(constant));
+			else
+				util::vector_erase_if_exists(status->endonend, static_cast<sc_type>(constant));
+		}
+	}
+
 	if (!exists) {
 		this->put(status_id, status);
 	}

+ 19 - 18
src/map/status.hpp

@@ -2940,27 +2940,28 @@ enum e_status_change_flag : uint16 {
 
 /// Struct of SC configs [Cydh]
 struct s_status_change_db {
-	sc_type type;					///< SC_
-	efst_type icon;					///< EFST_
-	std::bitset<SCS_MAX> state;		///< SCS_
-	std::bitset<SCB_MAX> calc_flag;	///< SCB_ flags
-	uint16 opt1;					///< OPT1_
-	uint16 opt2;					///< OPT2_
-	uint32 opt3;					///< OPT3_
-	uint32 look;					///< OPTION_ Changelook
-	std::bitset<SCF_MAX> flag;		///< SCF_ Flags, enum e_status_change_flag
-	bool display;					///< Display status effect/icon (for certain state)
-	uint16 skill_id;				///< Associated skill for (addeff) duration lookups
-	std::vector<sc_type> end;		///< List of SC that will be ended when this SC is activated
-	std::vector<sc_type> fail;		///< List of SC that causing this SC cannot be activated
-	std::vector<sc_type> endreturn;	///< List of SC that will be ended when this SC is activated and then immediately return
-	t_tick min_duration;			///< Minimum duration effect (after all status reduction)
-	uint16 min_rate;				///< Minimum rate to be applied (after all status reduction)
+	sc_type type;						///< SC_
+	efst_type icon;						///< EFST_
+	std::bitset<SCS_MAX> state;			///< SCS_
+	std::bitset<SCB_MAX> calc_flag;		///< SCB_ flags
+	uint16 opt1;						///< OPT1_
+	uint16 opt2;						///< OPT2_
+	uint32 opt3;						///< OPT3_
+	uint32 look;						///< OPTION_ Changelook
+	std::bitset<SCF_MAX> flag;			///< SCF_ Flags, enum e_status_change_flag
+	bool display;						///< Display status effect/icon (for certain state)
+	uint16 skill_id;					///< Associated skill for (addeff) duration lookups
+	std::vector<sc_type> endonstart;	///< List of SC that will be ended when this SC is activated
+	std::vector<sc_type> fail;			///< List of SC that causing this SC cannot be activated
+	std::vector<sc_type> endreturn;		///< List of SC that will be ended when this SC is activated and then immediately return
+	std::vector<sc_type> endonend;		///< List of SC that will be ended when this SC ends
+	t_tick min_duration;				///< Minimum duration effect (after all status reduction)
+	uint16 min_rate;					///< Minimum rate to be applied (after all status reduction)
 };
 
 class StatusDatabase : public TypesafeCachedYamlDatabase<uint16, s_status_change_db> {
 public:
-	StatusDatabase() : TypesafeCachedYamlDatabase("STATUS_DB", 2) {
+	StatusDatabase() : TypesafeCachedYamlDatabase("STATUS_DB", 3) {
 		// All except BASE and extra flags.
 		SCB_BATTLE.set();
 		SCB_BATTLE.reset(SCB_BASE);
@@ -2980,7 +2981,7 @@ public:
 	// Extras
 	efst_type getIcon(sc_type type);
 	std::bitset<SCB_MAX> getCalcFlag(sc_type type);
-	std::vector<sc_type> getEnd(sc_type type);
+	std::vector<sc_type> getEndOnStart(sc_type type);
 	uint16 getSkill(sc_type type);
 	bool hasSCF(status_change *sc, e_status_change_flag flag);
 	void removeByStatusFlag(block_list *bl, std::vector<e_status_change_flag> flag);

+ 29 - 0
src/tool/yamlupgrade.cpp

@@ -6,6 +6,7 @@
 static bool upgrade_achievement_db(std::string file, const uint32 source_version);
 static bool upgrade_item_db(std::string file, const uint32 source_version);
 static bool upgrade_job_stats(std::string file, const uint32 source_version);
+static bool upgrade_status_db(std::string file, const uint32 source_version);
 
 template<typename Func>
 bool process(const std::string &type, uint32 version, const std::vector<std::string> &paths, const std::string &name, Func lambda) {
@@ -121,6 +122,12 @@ int do_init(int argc, char** argv) {
 		})) {
 		return 0;
 	}
+	
+	if (!process("STATUS_DB", 3, root_paths, "status", [](const std::string& path, const std::string& name_ext, uint32 source_version) -> bool {
+		return upgrade_status_db(path + name_ext, source_version);
+		})) {
+		return 0;
+	}
 
 	return 0;
 }
@@ -293,3 +300,25 @@ static bool upgrade_job_stats(std::string file, const uint32 source_version) {
 
 	return true;
 }
+
+static bool upgrade_status_db(std::string file, const uint32 source_version) {
+	size_t entries = 0;
+
+	for (auto input : inNode["Body"]) {
+		// If under version 3
+		if (source_version < 3) {
+			// Rename End to EndOnStart
+			if (input["End"].IsDefined()) {
+				input["EndOnStart"] = input["End"];
+				input.remove("End");
+			}
+		}
+
+		body << input;
+		entries++;
+	}
+
+	ShowStatus("Done converting/upgrading '" CL_WHITE "%zu" CL_RESET "' statuses in '" CL_WHITE "%s" CL_RESET "'.\n", entries, file.c_str());
+
+	return true;
+}

部分文件因文件數量過多而無法顯示