소스 검색

Follow up to 2fc7472

Fixed an issue with random calculation on abra in some cases.
Moved some commonly used functions into util and yaml database for global usage.

Thanks to @Daegaladh and @aleos89
Lemongrass3110 5 년 전
부모
커밋
deb0615639
4개의 변경된 파일43개의 추가작업 그리고 15개의 파일을 삭제
  1. 8 0
      src/common/database.cpp
  2. 13 0
      src/common/database.hpp
  3. 14 0
      src/common/utilities.hpp
  4. 8 15
      src/map/skill.cpp

+ 8 - 0
src/common/database.cpp

@@ -249,6 +249,10 @@ bool YamlDatabase::asUInt16Rate( const YAML::Node& node, const std::string& name
 		if( out > maximum ){
 			this->invalidWarning( node[name], "Node \"%s\" with value %" PRIu16 " exceeds maximum of %" PRIu16 ".\n", name.c_str(), out, maximum );
 
+			return false;
+		}else if( out == 0 ){
+			this->invalidWarning( node[name], "Node \"%s\" needs to be at least 1.\n", name.c_str() );
+
 			return false;
 		}else{
 			return true;
@@ -263,6 +267,10 @@ bool YamlDatabase::asUInt32Rate( const YAML::Node& node, const std::string& name
 		if( out > maximum ){
 			this->invalidWarning( node[name], "Node \"%s\" with value %" PRIu32 " exceeds maximum of %" PRIu32 ".\n", name.c_str(), out, maximum );
 
+			return false;
+		}else if( out == 0 ){
+			this->invalidWarning( node[name], "Node \"%s\" needs to be at least 1.\n", name.c_str() );
+
 			return false;
 		}else{
 			return true;

+ 13 - 0
src/common/database.hpp

@@ -12,6 +12,7 @@
 
 #include "cbasetypes.hpp"
 #include "core.hpp"
+#include "utilities.hpp"
 
 class YamlDatabase{
 // Internal stuff
@@ -84,6 +85,10 @@ public:
 		this->data.clear();
 	}
 
+	bool empty(){
+		return this->data.empty();
+	}
+
 	bool exists( keytype key ){
 		return this->find( key ) != nullptr;
 	}
@@ -113,6 +118,14 @@ public:
 	size_t size(){
 		return this->data.size();
 	}
+
+	std::shared_ptr<datatype> random(){
+		if( this->empty() ){
+			return nullptr;
+		}
+
+		return rathena::util::umap_random( this->data );
+	}
 };
 
 #endif /* DATABASE_HPP */

+ 14 - 0
src/common/utilities.hpp

@@ -10,6 +10,7 @@
 #include <unordered_map>
 
 #include "cbasetypes.hpp"
+#include "random.hpp"
 
 // Class used to perform time measurement
 class cScopeTimer {
@@ -120,6 +121,19 @@ namespace rathena {
 			else
 				return defaultValue;
 		}
+
+		/**
+		 * Get a random value from the given map
+		 * @param map: Unordered Map to search through
+		 * @return A random value by reference
+		*/
+		template <typename K, typename V> V& umap_random( std::unordered_map<K, V>& map ){
+			auto it = map.begin();
+
+			std::advance( it, rnd_value( 0, map.size() - 1 ) );
+
+			return it->second;
+		}
 	}
 }
 

+ 8 - 15
src/map/skill.cpp

@@ -6410,20 +6410,23 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 		break;
 
 	case SA_ABRACADABRA:
-		if (abra_db.size() == 0) {
+		if (abra_db.empty()) {
 			clif_skill_nodamage (src, bl, skill_id, skill_lv, 1);
 			break;
 		}
 		else {
 			int abra_skill_id = 0, abra_skill_lv, checked = 0, checked_max = abra_db.size() * 3;
-			auto abra_spell = abra_db.begin();
 
 			do {
-				std::advance(abra_spell, rnd() % abra_db.size());
+				auto abra_spell = abra_db.random();
 
-				abra_skill_id = abra_spell->second->skill_id;
+				abra_skill_id = abra_spell->skill_id;
 				abra_skill_lv = min(skill_lv, skill_get_max(abra_skill_id));
-			} while (checked++ < checked_max && rnd() % 10000 >= abra_spell->second->per[max(skill_lv - 1, 0)]);
+
+				if( rnd() % 10000 < abra_spell->per[max(skill_lv - 1, 0)] ){
+					break;
+				}
+			} while (checked++ < checked_max);
 
 			if (!skill_get_index(abra_skill_id))
 				break;
@@ -21629,11 +21632,6 @@ uint64 AbraDatabase::parseBodyNode(const YAML::Node &node) {
 			if (!this->asUInt16Rate(probNode, "Probability", probability))
 				return 0;
 
-				if (!probability) {
-					this->invalidWarning(probNode["Probability"], "Probability has to be within the range of 1~10000, skipping.\n");
-					return 0;
-				}
-
 			abra->per.fill(probability);
 		} else {
 			abra->per.fill(0);
@@ -21652,11 +21650,6 @@ uint64 AbraDatabase::parseBodyNode(const YAML::Node &node) {
 				if (!this->asUInt16Rate(it, "Probability", probability))
 					continue;
 
-				if (!probability) {
-					this->invalidWarning(it["Probability"], "Probability has to be within the range of 1~10000, skipping.\n");
-					return 0;
-				}
-
 				abra->per[skill_lv - 1] = probability;
 			}
 		}