Import YCTIWY mod nearly unaltered

I had wanted this to be a standard feature of the
game for a while but put off merging it because:
- I had hoped to find a better visual design for the
  ghost player entities that matched the bandolier
  in nc_player_wield better, and
- I had scalability concerns with large servers with
  thousands of offline players.

However, in practice it seems like the scalability
issues are not as critical, and the visuals are
acceptable as they are for now.

In making this a standard game feature, it
will probably also make sense to add an option
to effectively disable parts of it (e.g. avoiding
creating the ents, or even avoiding filling the
database except where players' items are already
taken).
This commit is contained in:
Aaron Suen 2022-10-23 12:44:25 -04:00
parent 8f1a538452
commit 941d1545f2
7 changed files with 654 additions and 0 deletions

View File

@ -0,0 +1,404 @@
-- LUALOCALS < ---------------------------------------------------------
local ItemStack, math, minetest, nodecore, pairs, string, table, vector
= ItemStack, math, minetest, nodecore, pairs, string, table, vector
local math_pi, math_random, string_format, table_concat
= math.pi, math.random, string.format, table.concat
-- LUALOCALS > ---------------------------------------------------------
------------------------------------------------------------------------
-- DATABASE
local modname = minetest.get_current_modname()
local modstore = minetest.get_mod_storage()
local db = modstore:get_string("db")
if db == "" then db = nil end
db = db and minetest.deserialize(db)
db = db or {}
local drop = modstore:get_string("drop")
if drop == "" then drop = nil end
drop = drop and minetest.deserialize(drop)
drop = drop or {}
local function savedb()
modstore:set_string("db", minetest.serialize(db))
return modstore:set_string("drop", minetest.serialize(drop))
end
local function savestate(player, taken)
if not nodecore.player_visible(player) then
db[player:get_player_name()] = nil
return
end
local ent = {
pos = player:get_pos(),
inv = {},
taken = taken
}
ent.pos.y = ent.pos.y + 1
local inv = player:get_inventory()
for i = 1, inv:get_size("main") do
local stack = inv:get_stack("main", i)
ent.inv[i] = stack:to_string()
end
ent.seen = minetest.get_gametime()
db[player:get_player_name()] = ent
end
------------------------------------------------------------------------
-- MISC/UTILITY/COMMON
local function areaunloaded(pos)
local basepos = vector.floor(pos)
if minetest.get_node(pos).name == "ignore" then return true end
for dx = -1, 1, 2 do
for dy = -1, 1, 2 do
for dz = -1, 1, 2 do
if minetest.get_node({
x = basepos.x + dx,
y = basepos.y + dy,
z = basepos.z + dz
}).name == "ignore" then return true end
end
end
end
end
local function box(n) return {-n, -n, -n, n, n, n} end
local desctitle = nodecore.translate("Offline Player")
local function getdesc(pname, stack)
local d = desctitle .. "\n" .. nodecore.notranslate(pname)
if stack then return d .. "\n" .. nodecore.touchtip_stack(stack) end
return d
end
local function spawnentity(pos, subname, values)
if areaunloaded(pos) then return end
local o = minetest.add_entity(pos, modname .. ":" .. subname)
o = o and o:get_luaentity()
if not o then return end
nodecore.log("info", modname .. ": spawned " .. subname .. " at "
.. minetest.pos_to_string(pos, 2) .. (values.pname
and (" for " .. values.pname) or ""))
for k, v in pairs(values) do o[k] = v end
return o:yctiwy_check()
end
local function entrystack(entry, slot)
if not entry then return end
if entry.taken and entry.taken[slot] then return end
local stack = entry.inv and entry.inv[slot]
if (not stack) or (stack == "") then return end
stack = ItemStack(stack)
local def = minetest.registered_items[stack:get_name()]
if (not def) or def.virtual_item then return end
return stack
end
------------------------------------------------------------------------
-- INVENTORY ENTITIES
local thiefdata = {}
minetest.register_entity(modname .. ":slotent", {
initial_properties = nodecore.stackentprops(),
is_yctiwy = true,
slot = 1,
loose = 0,
yctiwy_check = function(self)
local ent = db[self.pname]
if minetest.get_player_by_name(self.pname) then
return self.object:remove()
end
local stack = entrystack(ent, self.slot)
if not stack then return self.object:remove() end
local props = nodecore.stackentprops(stack)
props.visual_size.x = props.visual_size.x / 2
props.visual_size.y = props.visual_size.y / 2
if props.is_visible then
props.collisionbox = box(0.2)
end
if not self.yawed then
self.yawed = true
self.object:set_yaw(math_random() * math_pi * 2)
end
self.rotating = self.rotating or (math_random(1, 2) == 1) and 0.1 or -0.1
props.automatic_rotate = self.rotating
self.object:set_properties(props)
self.description = getdesc(self.pname, stack)
end,
on_punch = function(self, puncher)
local ent = db[self.pname]
local punchname = puncher and puncher:get_player_name()
if not punchname then return end
local state = thiefdata[punchname]
if state and (state.target ~= self.pname or state.slot ~= self.slot
or state.exp < nodecore.gametime) then state = nil end
state = state or {
target = self.pname,
slot = self.slot,
final = nodecore.gametime + 2
}
state.exp = nodecore.gametime + 2
thiefdata[punchname] = state
if nodecore.gametime < state.final then return end
local stack = entrystack(ent, self.slot)
if not stack then return end
local function steallog(desc)
nodecore.log("action", string_format(
"%s: %q %s %q slot %d item %q at %s",
modname, puncher:get_player_name(), desc,
self.pname, self.slot, stack:to_string(),
minetest.pos_to_string(ent.pos, 0)))
end
local rp = vector.round(ent.pos)
if minetest.is_protected(rp, punchname) and
not minetest.is_protected(rp, self.pname) then
steallog("attempts to steal")
minetest.record_protection_violation(rp, punchname)
return
end
steallog("steals")
ent.taken = ent.taken or {}
ent.taken[self.slot] = true
savedb()
stack = puncher:get_inventory():add_item("main", stack)
if not stack:is_empty() then
nodecore.item_eject(self.object:get_pos(), stack)
end
return self.object:remove()
end
})
local s = 0.25
local offsets = {
{x = -s, y = -s, z = -s},
{x = s, y = -s, z = -s},
{x = -s, y = s, z = -s},
{x = s, y = s, z = -s},
{x = -s, y = -s, z = s},
{x = s, y = s, z = s},
{x = -s, y = s, z = s},
{x = s, y = -s, z = s}
}
local function spawninv(name, entry, existdb)
entry = entry or db[name]
if not entry then return end
for i = 1, #offsets do
if not existdb[name .. ":" .. i] and entrystack(entry, i) then
local p = vector.add(offsets[i], entry.pos)
spawnentity(p, "slotent", {
pname = name,
slot = i
})
end
end
end
------------------------------------------------------------------------
-- MARKER ENTITY
local function markertexture(pname)
-- XXX: new API, make required when released
if not nodecore.player_model_colors then return "nc_player_wield_slot.png" end
local colors = {nodecore.player_model_colors(pname)}
while #colors > 3 do colors[#colors] = nil end
for i = 1, #colors do
colors[i] = string_format("(%s_marker_%d.png^[multiply:%s)",
modname, i, colors[i])
end
return table_concat(colors, "^")
end
minetest.register_entity(modname .. ":marker", {
initial_properties = {
visual = "sprite",
textures = {"nc_player_wield_slot.png"},
collisionbox = box(0.1),
visual_size = {x = 0.2, y = 0.2},
is_visible = true,
static_save = false
},
is_yctiwy = true,
yctiwy_check = function(self)
if (not self.pname) or minetest.get_player_by_name(self.pname)
or (not minetest.player_exists(self.pname)) or (not db[self.pname]) then
return self.object:remove()
end
self.object:set_properties({textures = {markertexture(self.pname)}})
end,
on_punch = function(self)
self.object:set_properties({pointable = false})
self.pointtime = 2
self.on_step = function(me, dtime)
local pt = me.pointtime or 0
pt = pt - dtime
if pt > 0 then
me.pointtime = pt
else
me.object:set_properties({pointable = true})
me.pointtime = nil
me.on_step = nil
end
end
end
})
local function spawnmarker(name, entry, existdb)
if existdb[name .. ":"] then return end
entry = entry or db[name]
if not entry then return end
spawnentity(entry.pos, "marker", {
description = getdesc(name),
pname = name
})
end
------------------------------------------------------------------------
-- STOLEN ITEMS
local takenitem = modname .. ":taken"
nodecore.register_virtual_item(takenitem, {
description = "",
inventory_image = "[combine:1x1",
hotbar_type = "yctiwy_taken",
})
nodecore.register_aism({
itemnames = takenitem,
interval = 1,
chance = 1,
action = function(stack)
local exp = stack:get_meta():get_float("exp") or 0
if exp < nodecore.gametime then return "" end
end
})
------------------------------------------------------------------------
-- PLAYER HOOKS
minetest.register_on_leaveplayer(function(player)
savestate(player)
return savedb()
end)
minetest.register_on_shutdown(function()
for _, pl in pairs(minetest.get_connected_players()) do
savestate(pl)
end
return savedb()
end)
minetest.register_on_joinplayer(function(player)
local name = player:get_player_name()
local ent = db[name]
if (not ent) or (not ent.taken) then return end
local inv = player:get_inventory()
local takestack = ItemStack(takenitem)
takestack:get_meta():set_float("exp", nodecore.gametime + 4)
for k in pairs(ent.taken) do
inv:set_stack("main", k, takestack)
end
for _, o in pairs(minetest.luaentities) do
if o and o.is_yctiwy and o.pname == name then
o.object:remove()
end
end
end)
------------------------------------------------------------------------
-- TIMER
local function dumpinv(ent)
if areaunloaded(ent.pos) then return end
for k, v in pairs(ent.inv) do
if not (ent.taken and ent.taken[k]) then
local stack = ItemStack(v)
if not stack:is_empty() then
if minetest.add_item(ent.pos, stack) then
minetest.log(string_format("%s: deleted player %q"
.. " drops slot %d item %q at %s",
modname, ent.pname, k, stack:to_string(), minetest.pos_to_string(ent.pos, 0)))
ent.inv[k] = ""
else
return
end
end
end
end
return true
end
local function dropplayer(name, ent, skipsave)
ent = ent or db[name]
ent.pname = name
drop[#drop + 1] = ent
db[name] = nil
return skipsave or savedb()
end
local oldremove = minetest.remove_player
function minetest.remove_player(name, ...)
local function helper(...)
dropplayer(name)
return ...
end
return helper(oldremove(name, ...))
end
local timer = 0
minetest.register_globalstep(function(dtime)
timer = timer - dtime
if timer > 0 then return end
timer = 3 + math_random() * 2
for _, ent in pairs(minetest.luaentities) do
if ent.yctiwy_check then
ent:yctiwy_check()
end
end
local rollcall = {}
for _, pl in pairs(minetest.get_connected_players()) do
rollcall[pl:get_player_name()] = true
savestate(pl)
end
local existdb = {}
for _, ent in pairs(minetest.luaentities) do
if ent.is_yctiwy then
existdb[(ent.pname or "") .. ":" .. (ent.slot or "")] = true
end
end
for name, ent in pairs(db) do
if not minetest.player_exists(name) then
dropplayer(name, ent, true)
elseif not rollcall[name] then
spawnmarker(name, ent, existdb)
spawninv(name, ent, existdb)
end
end
local batch = drop
drop = {}
for _, ent in pairs(batch) do
if areaunloaded(ent.pos) then
drop[#drop + 1] = ent
else
if not dumpinv(ent) then drop[#drop + 1] = ent end
end
end
return savedb()
end)

View File

@ -0,0 +1,2 @@
name = nc_player_yctiwy
depends = nc_api_all, nc_player_health, nc_player_wield

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

View File

@ -0,0 +1,248 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64.90052mm"
height="64.90052mm"
viewBox="0 0 64.900519 64.900525"
version="1.1"
id="svg8"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="nc_yctiwy_slot_taken.svg"
inkscape:export-filename="taken.png"
inkscape:export-xdpi="395.28"
inkscape:export-ydpi="395.28">
<defs
id="defs2">
<linearGradient
inkscape:collect="always"
id="linearGradient4554">
<stop
style="stop-color:#fbfbfb;stop-opacity:0.50196081"
offset="0"
id="stop4550" />
<stop
style="stop-color:#000000;stop-opacity:0.97072071"
offset="1"
id="stop4552" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4554"
id="linearGradient4832"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-3.3218212,-3.321821,3.3218211,-3.3218211,-1387.3266,849.95437)"
x1="-178.47861"
y1="257.21585"
x2="-178.47861"
y2="269.08185" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4554"
id="linearGradient4941-7"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(4.5376921,-1.215871,1.215871,4.5376921,619.78624,-1261.5268)"
x1="-178.47861"
y1="257.21585"
x2="-178.47861"
y2="269.08185" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4554"
id="linearGradient3204"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2158709,-4.5376921,4.5376921,1.2158709,-827.5129,-999.97576)"
x1="-178.47861"
y1="257.21585"
x2="-178.47861"
y2="269.08185" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4554"
id="linearGradient3206"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-3.3218211,-3.321821,3.3218211,-3.321821,-1324.6526,384.19754)"
x1="-178.47861"
y1="257.21585"
x2="-178.47861"
y2="269.08185" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4554"
id="linearGradient3208"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(3.3218211,3.321821,-3.3218211,3.321821,1569.9456,-138.90457)"
x1="-178.47861"
y1="257.21585"
x2="-178.47861"
y2="269.08185" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4554"
id="linearGradient3210"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-1.2158709,4.5376921,-4.5376921,-1.2158708,1072.8059,1245.2687)"
x1="-178.47861"
y1="257.21585"
x2="-178.47861"
y2="269.08185" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4554"
id="linearGradient3212"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-4.5376921,1.2158709,-1.2158709,-4.5376921,-374.49319,1506.8197)"
x1="-178.47861"
y1="257.21585"
x2="-178.47861"
y2="269.08185" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter1171"
x="-0.5"
width="2"
y="-0.5"
height="2">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="3.4984423"
id="feGaussianBlur1173" />
</filter>
<mask
maskUnits="userSpaceOnUse"
id="mask1245">
<g
transform="translate(-6.4583338e-7,-2.1041666e-6)"
id="g1251"
style="stroke-width:0.99999994">
<circle
style="opacity:0.5;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="circle1247"
cx="-169.19171"
cy="250.74603"
r="19.853638" />
<path
sodipodi:nodetypes="cccccccccccccccccccccccccccscccccccsscccccccs"
inkscape:connector-curvature="0"
id="path1249"
transform="matrix(0.26458333,0,0,0.26458333,-201.57008,217.93825)"
d="m 97.308594,104.59766 c -5.731578,0.003 -10.160109,1.89981 -13.777344,3.71875 -3.61765,1.8192 -6.477956,3.45404 -9.652344,3.9707 -1.010099,0.16457 -2.277638,0.26313 -3.61914,0.33984 l -3.625,15.98828 c 2.761925,0.0414 5.347705,0.16792 7.222656,0.47266 3.178847,0.51685 6.035942,2.15672 9.658203,3.97656 3.622261,1.81985 8.057297,3.71849 13.794922,3.71875 5.732483,-0.003 10.161643,-1.89958 13.779293,-3.71875 3.61765,-1.81916 6.47214,-3.45986 9.64649,-3.97656 1.81164,-0.2948 3.73,-0.2948 5.54297,0 3.17911,0.51685 6.03571,2.15668 9.6582,3.97656 3.62253,1.81985 8.05711,3.71864 13.79492,3.71875 h 0.004 c 5.73248,-0.003 10.15579,-1.89958 13.77344,-3.71875 3.61765,-1.81916 6.47799,-3.45986 9.65234,-3.97656 1.00652,-0.16402 2.16946,-0.28527 3.39648,-0.38867 l 4.14063,-15.7832 c -2.83077,-0.10452 -5.447,-0.29393 -7.50977,-0.62891 -3.17884,-0.51681 -6.0418,-2.15672 -9.66406,-3.97656 -3.62226,-1.81985 -8.05733,-3.71263 -13.79492,-3.71289 -5.73271,0.003 -10.16146,1.89958 -13.7793,3.71875 -3.61788,1.81916 -6.47765,3.454 -9.65234,3.9707 -1.81164,0.2948 -3.72419,0.2948 -5.53711,0 -3.17885,-0.51681 -6.03594,-2.15672 -9.6582,-3.97656 -3.62181,-1.81962 -8.05637,-3.71218 -13.792973,-3.71289 z m 0.002,12.25195 c 3.593846,0 6.820526,0.77457 8.845706,1.78711 2.02515,1.0125 2.36719,1.92845 2.36719,2.05469 4e-5,0.12623 -0.34219,1.03614 -2.36719,2.04882 -2.02515,1.01265 -5.25137,1.78715 -8.845706,1.78711 -3.594369,4e-5 -6.820557,-0.77446 -8.845703,-1.78711 -2.025147,-1.01268 -2.367226,-1.92259 -2.367188,-2.04882 0,-0.12662 0.341852,-1.04219 2.367188,-2.05469 2.02526,-1.01254 5.251826,-1.78711 8.845703,-1.78711 z m 52.421876,0 c 3.59388,0 6.82048,0.77457 8.8457,1.78711 2.02515,1.0125 2.36719,1.92845 2.36719,2.05469 4e-5,0.12623 -0.34219,1.03614 -2.36719,2.04882 -2.02514,1.01265 -5.25133,1.78715 -8.8457,1.78711 -3.59433,4e-5 -6.82055,-0.77446 -8.8457,-1.78711 -2.02496,-1.01268 -2.36133,-1.92259 -2.36133,-2.04882 4e-5,-0.12662 0.33603,-1.04219 2.36133,-2.05469 2.02522,-1.0125 5.25186,-1.78711 8.8457,-1.78711 z"
style="fill:#ffffff;fill-opacity:1;stroke:#f9f9f9;stroke-width:18.51968575;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter1171)" />
</g>
</mask>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4554"
id="linearGradient1253"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-3.3218211,-3.321821,3.3218211,-3.321821,-1324.6526,384.19754)"
x1="-178.47861"
y1="257.21585"
x2="-178.47861"
y2="269.08185" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.4296006"
inkscape:cx="174.79492"
inkscape:cy="102.21482"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-bbox="true"
inkscape:object-paths="true"
inkscape:snap-global="false"
fit-margin-top="16"
fit-margin-left="16"
fit-margin-right="16"
fit-margin-bottom="16"
inkscape:bbox-paths="false"
inkscape:bbox-nodes="false"
inkscape:snap-bbox-edge-midpoints="false"
inkscape:snap-bbox-midpoints="false"
inkscape:snap-center="true"
inkscape:window-width="1366"
inkscape:window-height="718"
inkscape:window-x="0"
inkscape:window-y="21"
inkscape:window-maximized="1"
inkscape:pagecheckerboard="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(201.57012,-217.93821)">
<g
id="g1229"
mask="url(#mask1245)">
<path
id="path4762-7-65"
transform="matrix(0.26458333,0,0,0.26458333,-201.57008,217.93825)"
d="m 184.82031,105.98633 -16.875,4.52148 c 1.77094,0.82826 3.46371,1.48984 5.24414,1.7793 2.6026,0.4227 6.05277,0.62787 9.75391,0.70117 z m -35.08789,10.86328 c -3.59384,0 -6.82048,0.77461 -8.8457,1.78711 -2.0253,1.0125 -2.36129,1.92807 -2.36133,2.05469 0,0.12631 0.33618,1.03614 2.36133,2.04882 2.02515,1.01265 5.25137,1.78715 8.8457,1.78711 3.59437,4e-5 6.82056,-0.77446 8.8457,-1.78711 2.025,-1.01268 2.36723,-1.92259 2.36719,-2.04882 0,-0.12632 -0.34193,-1.04219 -2.36719,-2.05469 -2.02522,-1.01254 -5.25182,-1.78711 -8.8457,-1.78711 z m 29.04297,11.69336 c -2.08968,0.11611 -4.02091,0.28574 -5.61328,0.54492 -3.17435,0.5167 -6.03469,2.1574 -9.65234,3.97656 -3.61765,1.81917 -8.04096,3.71596 -13.77344,3.71875 a 3.5333755,3.5333755 0 0 1 -0.004,0 c -5.73781,-1.1e-4 -10.17239,-1.8989 -13.79492,-3.71875 -2.05064,-1.03021 -3.85419,-1.99462 -5.61133,-2.73828 l 37.83399,37.83399 z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#linearGradient3204);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path4762-7-2-6"
transform="matrix(0.26458333,0,0,0.26458333,-201.57008,217.93825)"
d="m 139.30664,60.472656 -13.91406,51.923824 c 0.30306,-0.0326 0.60774,-0.0608 0.90625,-0.10937 3.17469,-0.5167 6.03446,-2.15154 9.65234,-3.9707 3.61784,-1.81917 8.04659,-3.71599 13.7793,-3.71875 5.73759,2.6e-4 10.17266,1.89304 13.79492,3.71289 1.59348,0.80057 3.02897,1.54672 4.41992,2.19726 l 16.875,-4.52148 z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#linearGradient1253);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path4762-7-3-3"
transform="matrix(0.26458333,0,0,0.26458333,-201.57008,217.93825)"
d="m 120.92578,129.06445 c -0.0626,0.009 -0.12711,0.0133 -0.18945,0.0234 -3.17435,0.5167 -6.02884,2.1574 -9.64649,3.97656 -3.61765,1.81917 -8.04681,3.71596 -13.779293,3.71875 -5.691663,-2.6e-4 -10.098876,-1.8694 -13.705078,-3.67578 l -23.132813,6.19922 45.513674,45.51367 z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#linearGradient3208);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path4762-7-3-9-9"
transform="matrix(0.26458333,0,0,0.26458333,-201.57008,217.93825)"
d="m 77.132812,77.132812 -9.544921,35.619138 c 2.40034,-0.0604 4.628178,-0.19419 6.291015,-0.46484 3.174388,-0.51666 6.034694,-2.1515 9.652344,-3.9707 3.617228,-1.81895 8.045793,-3.71555 13.777344,-3.71875 h 0.002 c 3.372416,4.1e-4 6.285426,0.66154 8.857426,1.57031 z m 20.177735,39.716798 c -3.593877,0 -6.820443,0.77457 -8.845703,1.78711 -2.025336,1.0125 -2.367188,1.92807 -2.367188,2.05469 -3.8e-5,0.12631 0.342041,1.03614 2.367188,2.04882 2.025146,1.01265 5.251334,1.78715 8.845703,1.78711 3.594333,4e-5 6.820553,-0.77446 8.845703,-1.78711 2.025,-1.01268 2.36723,-1.92259 2.36719,-2.04882 0,-0.12632 -0.34193,-1.04219 -2.36719,-2.05469 -2.02518,-1.01254 -5.25186,-1.78711 -8.845703,-1.78711 z m -33.966797,11.74023 -2.871094,10.7168 23.132813,-6.19922 c -0.02912,-0.0146 -0.06083,-0.0284 -0.08984,-0.043 -3.622261,-1.81984 -6.479356,-3.45971 -9.658203,-3.97656 -2.61224,-0.42466 -6.558729,-0.5299 -10.513672,-0.49805 z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#linearGradient3210);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path4762-7-3-9-2-48"
transform="matrix(0.26458333,0,0,0.26458333,-201.57008,217.93825)"
d="M 139.30664,60.472656 77.132812,77.132812 106.16797,106.16797 c 1.80305,0.63708 3.44291,1.39267 4.93555,2.14258 3.62226,1.81984 6.47935,3.45975 9.6582,3.97656 1.51421,0.24623 3.09464,0.27446 4.63086,0.10937 z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#linearGradient3212);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
transform="matrix(0.26458333,0,0,0.26458333,-201.57008,217.93825)"
id="path4762-7-65-7"
d="m 123.50781,128.86719 c -0.86823,0 -1.73528,0.0695 -2.58203,0.19726 l -14.93945,55.75586 62.17383,-16.66015 -37.83399,-37.83399 c -1.34687,-0.57002 -2.66741,-1.01401 -4.04687,-1.23828 -0.90649,-0.1474 -1.83909,-0.2207 -2.77149,-0.2207 z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#linearGradient4941-7);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path4601-5-1"
transform="matrix(0.26458333,0,0,0.26458333,-201.57008,217.93825)"
d="M 138.7168,62.673828 78.744141,78.744141 69.654297,112.66602 c 1.578008,-0.0799 3.058897,-0.18917 4.224609,-0.37891 3.174388,-0.51666 6.034694,-2.1515 9.652344,-3.9707 3.617228,-1.81895 8.045793,-3.71555 13.777344,-3.71875 h 0.002 c 5.736576,7e-4 10.171136,1.89326 13.792976,3.71289 3.62226,1.81984 6.47935,3.45975 9.6582,3.97656 1.81292,0.2948 3.72547,0.2948 5.53711,0 3.17469,-0.5167 6.03446,-2.15154 9.65234,-3.9707 3.61784,-1.81917 8.04659,-3.71599 13.7793,-3.71875 5.73759,2.6e-4 10.17266,1.89304 13.79492,3.71289 3.62226,1.81984 6.48522,3.45975 9.66406,3.97656 2.1179,0.34398 4.80803,0.53813 7.72657,0.64062 l 1.70312,-6.35156 z M 97.310547,116.84961 c -3.593877,0 -6.820443,0.77457 -8.845703,1.78711 -2.025336,1.0125 -2.367188,1.92807 -2.367188,2.05469 -3.8e-5,0.12631 0.342041,1.03614 2.367188,2.04882 2.025146,1.01265 5.251334,1.78715 8.845703,1.78711 3.594333,4e-5 6.820553,-0.77446 8.845703,-1.78711 2.025,-1.01268 2.36723,-1.92259 2.36719,-2.04882 0,-0.12632 -0.34193,-1.04219 -2.36719,-2.05469 -2.02518,-1.01254 -5.25186,-1.78711 -8.845703,-1.78711 z m 52.421873,0 c -3.59384,0 -6.82048,0.77461 -8.8457,1.78711 -2.0253,1.0125 -2.36129,1.92807 -2.36133,2.05469 0,0.12631 0.33618,1.03614 2.36133,2.04882 2.02515,1.01265 5.25137,1.78715 8.8457,1.78711 3.59437,4e-5 6.82056,-0.77446 8.8457,-1.78711 2.025,-1.01268 2.36723,-1.92259 2.36719,-2.04882 0,-0.12632 -0.34193,-1.04219 -2.36719,-2.05469 -2.02522,-1.01254 -5.25182,-1.78711 -8.8457,-1.78711 z m -84.347654,11.74805 -2.710938,10.11914 43.902342,43.90234 59.97266,-16.07031 10.14648,-37.86328 c -1.27935,0.10568 -2.48814,0.23224 -3.5332,0.40234 -3.17435,0.5167 -6.03469,2.1574 -9.65234,3.97656 -3.61765,1.81917 -8.04096,3.71596 -13.77344,3.71875 a 3.5333755,3.5333755 0 0 1 -0.004,0 c -5.73781,-1.1e-4 -10.17239,-1.8989 -13.79492,-3.71875 -3.62249,-1.81988 -6.47909,-3.45971 -9.6582,-3.97656 -1.81297,-0.2948 -3.73133,-0.2948 -5.54297,0 -3.17435,0.5167 -6.02884,2.1574 -9.64649,3.97656 -3.61765,1.81917 -8.04681,3.71596 -13.779293,3.71875 -5.737625,-2.6e-4 -10.172661,-1.8989 -13.794922,-3.71875 -3.622261,-1.81984 -6.479356,-3.45971 -9.658203,-3.97656 -2.157957,-0.35081 -5.241929,-0.47152 -8.472656,-0.49023 z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4.4031496;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB