aboutsummaryrefslogtreecommitdiff
path: root/src/client/tile.cpp
Commit message (Expand)AuthorAge
* Remove dead code (#10845)rubenwardy2021-01-22
* Fix some minor code issues all over the placesfan52020-12-24
* Stop wasting memory on identical textures when texture filtering is disabledsfan52020-05-20
* Overall improvements to log messages (#9598)sfan52020-04-08
* Correction for alpha blending issues in texture mod compositing (#9029)Warr10242019-10-18
* Textures: Load base pack only as last fallback (#8974)SmallJoker2019-09-29
* Unify GLES support in gui scaling filtersfan52019-08-04
* Unify OpenGL ES supportsfan52019-08-04
* Optimize string (mis)handling (#8128)Jozef Behran2019-05-18
* Import strstr function from FreeBSD 11 libcLoic Blot2019-01-10
* Android build fixesLoïc Blot2019-01-09
* Fix a crash on Android with Align2Npot2 (#8070)Loïc Blot2019-01-07
* Software inventorycube (#7651)Vitaliy2018-09-29
* Android build fixes for c++11stujones112018-03-11
* Drop texture file list cache (#6660)Vitaliy2018-03-10
* Load files from subfolders in texturepacksnumber Zero2017-11-17
* Do not scale texture unless necessary.Lars Hofhansl2017-11-04
* Real global textures (#6105)Vitaliy2017-10-15
* Code modernization: subfolders (#6283)Loïc Blot2017-08-19
* Modernize client code (#6250)Loïc Blot2017-08-15
* Isolate irrlicht references and use a singleton (#6041)Loïc Blot2017-06-26
* Remove threads.h and replace its definitions with their C++11 equivalents (#5...ShadowNinja2017-06-11
* Use C++11 mutexes only (remove compat code) (#5922)Loïc Blot2017-06-06
* C++11 patchset 2: remove util/cpp11.h and util/cpp11_container.h (#5821)Loïc Blot2017-06-04
* Do not create dummy normalmaps (#4180)you2017-05-19
* Remove an unused variable in Android BuildLoic Blot2017-04-17
* Android progressbar fix (#5601)Loïc Blot2017-04-16
* Hardware coloring for itemstacksDániel Juhász2017-04-08
* Tile.cpp: Fix MSVC build broken by 072bbbaSmallJoker2017-03-24
* Some performance optimizations (#5424)Loïc Blot2017-03-22
* Prevent SIGFPE on entity tile loading issue. (#5178)Auke Kok2017-02-05
* Add multiply texture modifiersapier2017-01-30
* Add hardware node coloring. Includes:Dániel Juhász2017-01-23
* Added "[sheet" to the texture special commands.Luke Puchner-Hardman2017-01-02
* Irrlicht 1.9 supportsfan52016-12-26
* Add an [invert:<mode> texture modifierThomas--S2016-09-15
* Allow escaping of texture names when passed as an argument to a modifiersfan52016-09-14
* Add an [opacity:<r> texture modifier. Makes the base image transparent accord...Thomas--S2016-08-12
* Add [resize texture modifier Resizes the texture to the given dimensions.SmallJoker2016-05-09
* tile.cpp: Automatically upscale lower resolution textureSmallJoker2016-04-25
* Re-add and disable blit_with_interpolate_overlaykwolekr2016-04-07
* Fix compiler warnings from "Add an option to colorize to respect the destinat...Samuel Sieb2016-04-06
* Add an option to colorize to respect the destination alphaSamuel Sieb2016-04-03
* Clean up StrfndShadowNinja2016-03-19
* Refactor thread utility interfacekwolekr2015-10-16
* Change i++ to ++iDavid Jones2015-08-25
* Clean up threadingShadowNinja2015-08-23
* Remove use of engine sent texture tiling flags - theyre no longer neededRealBadAngel2015-08-20
* src/client/tile.cpp: Fix reference countingBřetislav Štec2015-08-02
* Add wielded (and CAOs) shaderRealBadAngel2015-07-21
">(Json::Value &object) const { object["maxlevel"] = maxlevel; object["uses"] = uses; Json::Value times_object; for (auto time : times) times_object[time.first] = time.second; object["times"] = times_object; } void ToolGroupCap::fromJson(const Json::Value &json) { if (json.isObject()) { if (json["maxlevel"].isInt()) maxlevel = json["maxlevel"].asInt(); if (json["uses"].isInt()) uses = json["uses"].asInt(); const Json::Value &times_object = json["times"]; if (times_object.isArray()) { Json::ArrayIndex size = times_object.size(); for (Json::ArrayIndex i = 0; i < size; ++i) if (times_object[i].isDouble()) times[i] = times_object[i].asFloat(); } } } void ToolCapabilities::serialize(std::ostream &os, u16 protocol_version) const { if (protocol_version >= 38) writeU8(os, 5); else writeU8(os, 4); // proto == 37 writeF32(os, full_punch_interval); writeS16(os, max_drop_level); writeU32(os, groupcaps.size()); for (const auto &groupcap : groupcaps) { const std::string *name = &groupcap.first; const ToolGroupCap *cap = &groupcap.second; os << serializeString16(*name); writeS16(os, cap->uses); writeS16(os, cap->maxlevel); writeU32(os, cap->times.size()); for (const auto &time : cap->times) { writeS16(os, time.first); writeF32(os, time.second); } } writeU32(os, damageGroups.size()); for (const auto &damageGroup : damageGroups) { os << serializeString16(damageGroup.first); writeS16(os, damageGroup.second); } if (protocol_version >= 38) writeU16(os, rangelim(punch_attack_uses, 0, U16_MAX)); } void ToolCapabilities::deSerialize(std::istream &is) { int version = readU8(is); if (version < 4) throw SerializationError("unsupported ToolCapabilities version"); full_punch_interval = readF32(is); max_drop_level = readS16(is); groupcaps.clear(); u32 groupcaps_size = readU32(is); for (u32 i = 0; i < groupcaps_size; i++) { std::string name = deSerializeString16(is); ToolGroupCap cap; cap.uses = readS16(is); cap.maxlevel = readS16(is); u32 times_size = readU32(is); for(u32 i = 0; i < times_size; i++) { int level = readS16(is); float time = readF32(is); cap.times[level] = time; } groupcaps[name] = cap; } u32 damage_groups_size = readU32(is); for (u32 i = 0; i < damage_groups_size; i++) { std::string name = deSerializeString16(is); s16 rating = readS16(is); damageGroups[name] = rating; } if (version >= 5) punch_attack_uses = readU16(is); } void ToolCapabilities::serializeJson(std::ostream &os) const { Json::Value root; root["full_punch_interval"] = full_punch_interval; root["max_drop_level"] = max_drop_level; root["punch_attack_uses"] = punch_attack_uses; Json::Value groupcaps_object; for (const auto &groupcap : groupcaps) { groupcap.second.toJson(groupcaps_object[groupcap.first]); } root["groupcaps"] = groupcaps_object; Json::Value damage_groups_object; DamageGroup::const_iterator dgiter; for (dgiter = damageGroups.begin(); dgiter != damageGroups.end(); ++dgiter) { damage_groups_object[dgiter->first] = dgiter->second; } root["damage_groups"] = damage_groups_object; fastWriteJson(root, os); } void ToolCapabilities::deserializeJson(std::istream &is) { Json::Value root; is >> root; if (root.isObject()) { if (root["full_punch_interval"].isDouble()) full_punch_interval = root["full_punch_interval"].asFloat(); if (root["max_drop_level"].isInt()) max_drop_level = root["max_drop_level"].asInt(); if (root["punch_attack_uses"].isInt()) punch_attack_uses = root["punch_attack_uses"].asInt(); Json::Value &groupcaps_object = root["groupcaps"]; if (groupcaps_object.isObject()) { Json::ValueIterator gciter; for (gciter = groupcaps_object.begin(); gciter != groupcaps_object.end(); ++gciter) { ToolGroupCap groupcap; groupcap.fromJson(*gciter); groupcaps[gciter.key().asString()] = groupcap; } } Json::Value &damage_groups_object = root["damage_groups"]; if (damage_groups_object.isObject()) { Json::ValueIterator dgiter; for (dgiter = damage_groups_object.begin(); dgiter != damage_groups_object.end(); ++dgiter) { Json::Value &value = *dgiter; if (value.isInt()) damageGroups[dgiter.key().asString()] = value.asInt(); } } } } static u32 calculateResultWear(const u32 uses, const u16 initial_wear) { if (uses == 0) { // Trivial case: Infinite uses return 0; } /* Finite uses. This is not trivial, as the maximum wear is not neatly evenly divisible by most possible uses numbers. For example, for 128 uses, the calculation of wear is trivial, as 65536 / 128 uses = 512 wear, so the tool will get 512 wear 128 times in its lifetime. But for a number like 130, this does not work: 65536 / 130 uses = 504.123... wear. Since wear must be an integer, we will get 504*130 = 65520, which would lead to the wrong number of uses. Instead, we partition the "wear range" into blocks: A block represents a single use and can be of two possible sizes: normal and oversized. A normal block is equal to floor(65536 / uses). An oversized block is a normal block plus 1. Then we determine how many oversized and normal blocks we need and finally, whether we add the normal wear or the oversized wear. Example for 130 uses: * Normal wear = 504 * Number of normal blocks = 114 * Oversized wear = 505 * Number of oversized blocks = 16 If we add everything together, we get: 114*504 + 16*505 = 65536 */ u32 result_wear; u32 wear_normal = ((U16_MAX+1) / uses); // Will be non-zero if its not evenly divisible u16 blocks_oversize = (U16_MAX+1) % uses; // Whether to add one extra wear point in case // of oversized wear. u16 wear_extra = 0; if (blocks_oversize > 0) { u16 blocks_normal = uses - blocks_oversize; /* When the wear has reached this value, we know that wear_normal has been applied for blocks_normal times, therefore, only oversized blocks remain. This also implies the raw tool wear number increases a bit faster after this point, but this should be barely noticable by the player. */ u16 wear_extra_at = blocks_normal * wear_normal; if (initial_wear >= wear_extra_at) { wear_extra = 1; } } result_wear = wear_normal + wear_extra; return result_wear; } DigParams getDigParams(const ItemGroupList &groups, const ToolCapabilities *tp, const u16 initial_wear) { // Group dig_immediate defaults to fixed time and no wear if (tp->groupcaps.find("dig_immediate") == tp->groupcaps.cend()) { switch (itemgroup_get(groups, "dig_immediate")) { case 2: return DigParams(true, 0.5, 0, "dig_immediate"); case 3: return DigParams(true, 0, 0, "dig_immediate"); default: break; } } // Values to be returned (with a bit of conversion) bool result_diggable = false; float result_time = 0.0; u32 result_wear = 0; std::string result_main_group; int level = itemgroup_get(groups, "level"); for (const auto &groupcap : tp->groupcaps) { const ToolGroupCap &cap = groupcap.second; int leveldiff = cap.maxlevel - level; if (leveldiff < 0) continue; const std::string &groupname = groupcap.first; float time = 0; int rating = itemgroup_get(groups, groupname); bool time_exists = cap.getTime(rating, &time); if (!time_exists) continue; if (leveldiff > 1) time /= leveldiff; if (!result_diggable || time < result_time) { result_time = time; result_diggable = true; // The actual number of uses increases // exponentially with leveldiff. // If the levels are equal, real_uses equals cap.uses. u32 real_uses = cap.uses * pow(3.0, leveldiff); real_uses = MYMIN(real_uses, U16_MAX); result_wear = calculateResultWear(real_uses, initial_wear); result_main_group = groupname; } } return DigParams(result_diggable, result_time, result_wear, result_main_group); } HitParams getHitParams(const ItemGroupList &armor_groups, const ToolCapabilities *tp, float time_from_last_punch, u16 initial_wear) { s16 damage = 0; float result_wear = 0.0f; float punch_interval_multiplier = rangelim(time_from_last_punch / tp->full_punch_interval, 0.0f, 1.0f); for (const auto &damageGroup : tp->damageGroups) { s16 armor = itemgroup_get(armor_groups, damageGroup.first); damage += damageGroup.second * punch_interval_multiplier * armor / 100.0; } if (tp->punch_attack_uses > 0) { result_wear = calculateResultWear(tp->punch_attack_uses, initial_wear); result_wear *= punch_interval_multiplier; } u32 wear_i = (u32) result_wear; return {damage, wear_i}; } HitParams getHitParams(const ItemGroupList &armor_groups, const ToolCapabilities *tp) { return getHitParams(armor_groups, tp, 1000000); } PunchDamageResult getPunchDamage( const ItemGroupList &armor_groups, const ToolCapabilities *toolcap, const ItemStack *punchitem, float time_from_last_punch, u16 initial_wear ){ bool do_hit = true; { if (do_hit && punchitem) { if (itemgroup_get(armor_groups, "punch_operable") && (toolcap == NULL || punchitem->name.empty())) do_hit = false; } if (do_hit) { if(itemgroup_get(armor_groups, "immortal")) do_hit = false; } } PunchDamageResult result; if(do_hit) { HitParams hitparams = getHitParams(armor_groups, toolcap, time_from_last_punch, punchitem->wear); result.did_punch = true; result.wear = hitparams.wear; result.damage = hitparams.hp; } return result; } f32 getToolRange(const ItemDefinition &def_selected, const ItemDefinition &def_hand) { float max_d = def_selected.range; float max_d_hand = def_hand.range; if (max_d < 0 && max_d_hand >= 0) max_d = max_d_hand; else if (max_d < 0) max_d = 4.0f; return max_d; }