code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" x="0px" y="0px" viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve" id="svg4356" sodipodi:docname="vector source.svg" inkscape:version="0.91 r13725">
  <metadata id="metadata4362">
	<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>
  <defs id="defs4360"/>
  <sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1280" inkscape:window-height="952" id="namedview4358" showgrid="false" inkscape:zoom="1.2020815" inkscape:cx="434.47578" inkscape:cy="639.70571" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="svg4356" inkscape:object-nodes="true" inkscape:object-paths="false" inkscape:snap-smooth-nodes="true"/>
  <style type="text/css" id="style3680">
	.st0{fill:#FFFFFF;}
	.st1{fill:#76C043;}
	.st2{fill:#2680BC;}
	.st3{fill:#F6E0E8;}
	.st4{fill:#515351;}
	.st5{fill:#F4F1A3;}
	.st6{fill:#8E4F21;}
	.st7{fill:#BC2027;}
	.st8{fill:#60BB46;}
	.st9{fill:#4686C6;}
	.st10{fill:#D28DBD;}
	.st11{fill:#3F403F;}
	.st12{fill:#010101;}
	.st13{fill:#8F8F8E;}
	.st14{fill:#515251;}
	.st15{fill:#4F6AB2;}
	.st16{fill:#3E65B0;}
	.st17{fill:#15406D;}
	.st18{fill:#65AD45;}
	.st19{fill:#787878;}
	.st20{fill:#D76B93;}
	.st21{fill:#4DB748;}
	.st22{opacity:0.24;fill:#BF2126;enable-background:new	;}
	.st23{fill:#070505;}
	.st24{fill:#BF2126;}
</style>
  <svg:g inkscape:groupmode="layer" id="Boob_7_straps" inkscape:label="Boob_7_straps" style="display:inline">
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 508.3,214.2 C 449.714,298.729 270.477,341.098 261.246,450.171" id="path7375" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 526.574,459.199 C 539.97,365.712 508.179,303.374 508.3,214.2" id="path7377" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 522.623,503.54 C 520.28,528.215 548.507,555.384 559.839,561.514" id="path7381" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 265.667,486.42 C 267.838,510.591 306.187,531.841 350.216,534.498" id="path7383" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 499.189,481.381 C 474.478,479.681 457.992,487.065 442,477.868" id="path7385" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 275.097,469.249 C 319.63,474.712 396.528,483.662 442,477.868" id="path7387" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 441.823,481.362 L 442,477.868 C 439.051,391.71 464.477,303.109 508.3,214.2" id="path7389" inkscape:connector-curvature="0" sodipodi:nodetypes="ccc"/>
	<svg:path style="display:inline;fill:none;stroke:#b3b3b3;stroke-width:1.29999995;stroke-miterlimit:4;stroke-dasharray:none" inkscape:connector-curvature="0" d="M 259.85,450.536 C 266.525,449.41 273.01,458.259 274.177,464.926 C 275.502,472.49 273.446,485.122 265.876,486.417 C 259.054,487.584 254.245,476.862 253.121,470.032 C 252.004,463.249 253.071,451.68 259.85,450.536 Z" class="st20" id="path7391" sodipodi:nodetypes="ccccc"/>
	<svg:path style="display:inline;fill:none;stroke:#b3b3b3;stroke-width:1.29999983;stroke-miterlimit:4;stroke-dasharray:none" d="M 526.065,503.352 C 515.208,504.067 500.738,494.532 500.023,483.676 C 499.297,472.661 511.737,460.317 522.752,459.592 C 533.609,458.877 548.079,468.412 548.794,479.268 C 549.52,490.283 537.08,502.627 526.065,503.352 Z" id="path7393" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
	<svg:path id="path9222-3" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 549.048,483.92 C 589.096,483.618 639.217,446.836 663.654,430.681 C 676.663,352.064 522.885,295.117 508.3,214.2" inkscape:connector-curvature="0" sodipodi:nodetypes="ccc"/>
  </svg:g>
</svg>


repo_name: KnightBoulegard/fc

path: resources/vector/outfit/boot latex.svg

license: mit


path: resources/vector/outfit/boot wide.svg


path: resources/vector/outfit/chastity male fore 0.svg


path: resources/vector/outfit/chastity male fore 1.svg


path: resources/vector/outfit/chastity male fore 2.svg


path: resources/vector/outfit/chastity male fore 3.svg


path: resources/vector/outfit/chastity male fore 4.svg


path: resources/vector/outfit/chastity male fore 5.svg


path: resources/vector/outfit/chastity male fore 6.svg


path: resources/vector/outfit/dildo gag.svg


path: resources/vector/outfit/extreme heel wide latex.svg


path: resources/vector/outfit/flat latex.svg


path: resources/vector/outfit/head latex.svg


path: resources/vector/outfit/heavy gold.svg


path: resources/vector/outfit/heel latex.svg


path: resources/vector/outfit/neck corset.svg


path: resources/vector/outfit/tight steel.svg


code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" x="0px" y="0px" viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve" id="svg4356" sodipodi:docname="vector source.svg" inkscape:version="0.91 r13725">
  <metadata id="metadata4362">
	<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>
  <defs id="defs4360"/>
  <sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1280" inkscape:window-height="952" id="namedview4358" showgrid="false" inkscape:zoom="4.808326" inkscape:cx="531.76051" inkscape:cy="751.71421" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="Boob_Large_3_" inkscape:object-nodes="true" inkscape:object-paths="false" inkscape:snap-smooth-nodes="true" inkscape:snap-object-midpoints="true"/>
  <style type="text/css" id="style3680">
	.st0{fill:#FFFFFF;}
	.st1{fill:#76C043;}
	.st2{fill:#2680BC;}
	.st3{fill:#F6E0E8;}
	.st4{fill:#515351;}
	.st5{fill:#F4F1A3;}
	.st6{fill:#8E4F21;}
	.st7{fill:#BC2027;}
	.st8{fill:#60BB46;}
	.st9{fill:#4686C6;}
	.st10{fill:#D28DBD;}
	.st11{fill:#3F403F;}
	.st12{fill:#010101;}
	.st13{fill:#8F8F8E;}
	.st14{fill:#515251;}
	.st15{fill:#4F6AB2;}
	.st16{fill:#3E65B0;}
	.st17{fill:#15406D;}
	.st18{fill:#65AD45;}
	.st19{fill:#787878;}
	.st20{fill:#D76B93;}
	.st21{fill:#4DB748;}
	.st22{opacity:0.24;fill:#BF2126;enable-background:new	;}
	.st23{fill:#070505;}
	.st24{fill:#BF2126;}
</style>
  <svg:g inkscape:groupmode="layer" id="Torso_Hourglass_straps" inkscape:label="Torso_Hourglass_straps" style="display:inline">
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m 500.97796,204.16551 c -0.71264,4.69149 3.72511,8.09539 9.22204,11.23449 12.56584,-0.1687 25.13169,-3.25605 37.69753,-9.69857" id="path9218" inkscape:connector-curvature="0" sodipodi:nodetypes="ccc"/>
	<svg:path id="path9222" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" d="m 495.8,467.5 -14.5431,-61.0527 4.91522,-55.28426 5.08461,-71.0825 L 510.2,215.4 530.35082,279.04329 523.449,317.775 508.76009,353.35994 481.2569,406.4473 471.9861,352.02373 461.91384,309.87756 468.81988,275.6 510.2,215.4" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc"/>
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m 463.2324,352.85095 8.7537,-0.82722 14.18602,-0.86069 22.58797,2.1969 37.46362,7.77538" id="path9224" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m 460.59329,375.71105 c 8.26177,10.3193 15.11821,15.52324 20.66361,30.73625 14.56337,-16.56115 48.05529,-16.49869 68.44366,-26.50672" id="path9226" inkscape:connector-curvature="0" sodipodi:nodetypes="ccc"/>
	<svg:path id="path4809" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m 587.45053,268.9835 -27.76453,10.0025 -29.33518,0.0573 -39.09409,1.03724 -22.43685,-4.48053 -8.85992,-2.64861" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccc"/>
  </svg:g>
</svg>


code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" x="0px" y="0px" viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve" id="svg4356" sodipodi:docname="vector source.svg" inkscape:version="0.91 r13725">
  <metadata id="metadata4362">
	<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>
  <defs id="defs4360"/>
  <sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1280" inkscape:window-height="952" id="namedview4358" showgrid="false" inkscape:zoom="4.808326" inkscape:cx="531.76051" inkscape:cy="751.71421" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="Boob_Large_3_" inkscape:object-nodes="true" inkscape:object-paths="false" inkscape:snap-smooth-nodes="true" inkscape:snap-object-midpoints="true"/>
  <style type="text/css" id="style3680">
	.st0{fill:#FFFFFF;}
	.st1{fill:#76C043;}
	.st2{fill:#2680BC;}
	.st3{fill:#F6E0E8;}
	.st4{fill:#515351;}
	.st5{fill:#F4F1A3;}
	.st6{fill:#8E4F21;}
	.st7{fill:#BC2027;}
	.st8{fill:#60BB46;}
	.st9{fill:#4686C6;}
	.st10{fill:#D28DBD;}
	.st11{fill:#3F403F;}
	.st12{fill:#010101;}
	.st13{fill:#8F8F8E;}
	.st14{fill:#515251;}
	.st15{fill:#4F6AB2;}
	.st16{fill:#3E65B0;}
	.st17{fill:#15406D;}
	.st18{fill:#65AD45;}
	.st19{fill:#787878;}
	.st20{fill:#D76B93;}
	.st21{fill:#4DB748;}
	.st22{opacity:0.24;fill:#BF2126;enable-background:new	;}
	.st23{fill:#070505;}
	.st24{fill:#BF2126;}
</style>
  <svg:g inkscape:groupmode="layer" id="Torso_Normal_straps" inkscape:label="Torso_Normal_straps" style="display:inline">
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 500.903,204.256 C 500.191,208.948 504.628,212.352 510.125,215.491 C 522.07,215.33 533.649,211.074 545.594,204.95" id="path9218" inkscape:connector-curvature="0" sodipodi:nodetypes="ccc"/>
	<svg:path id="path9222" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" d="M 492.779,466.2 L 479.154,404.326 L 481.969,348.317 L 491.442,278.56 L 510.125,215.491 L 531.396,274.432 L 535.475,313.426 L 525.004,352.471 L 479.154,404.326 L 467.783,349.178 L 461.718,308.021 L 469.006,274.079 L 510.125,215.491" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc"/>
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 459.029,350.005 L 467.783,349.178 L 481.969,348.317 L 525.004,352.471 L 562.468,360.247" id="path9224" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 458.065,372.805 C 466.525,383.372 473.476,388.748 479.154,404.326 C 495.782,385.418 536.776,393.898 560.054,382.472" id="path9226" inkscape:connector-curvature="0" sodipodi:nodetypes="ccc"/>
	<svg:path id="path4809" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 587.622,264.803 L 560.344,274.43 L 531.396,274.432 L 491.442,278.56 L 469.006,274.079 L 460.146,271.43" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccc"/>
  </svg:g>
</svg>


code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" x="0px" y="0px" viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve" id="svg4356" sodipodi:docname="vector source.svg" inkscape:version="0.91 r13725">
  <metadata id="metadata4362">
	<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>
  <defs id="defs4360"/>
  <sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1280" inkscape:window-height="952" id="namedview4358" showgrid="false" inkscape:zoom="4.808326" inkscape:cx="531.76051" inkscape:cy="751.71421" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="Boob_Large_3_" inkscape:object-nodes="true" inkscape:object-paths="false" inkscape:snap-smooth-nodes="true" inkscape:snap-object-midpoints="true"/>
  <style type="text/css" id="style3680">
	.st0{fill:#FFFFFF;}
	.st1{fill:#76C043;}
	.st2{fill:#2680BC;}
	.st3{fill:#F6E0E8;}
	.st4{fill:#515351;}
	.st5{fill:#F4F1A3;}
	.st6{fill:#8E4F21;}
	.st7{fill:#BC2027;}
	.st8{fill:#60BB46;}
	.st9{fill:#4686C6;}
	.st10{fill:#D28DBD;}
	.st11{fill:#3F403F;}
	.st12{fill:#010101;}
	.st13{fill:#8F8F8E;}
	.st14{fill:#515251;}
	.st15{fill:#4F6AB2;}
	.st16{fill:#3E65B0;}
	.st17{fill:#15406D;}
	.st18{fill:#65AD45;}
	.st19{fill:#787878;}
	.st20{fill:#D76B93;}
	.st21{fill:#4DB748;}
	.st22{opacity:0.24;fill:#BF2126;enable-background:new	;}
	.st23{fill:#070505;}
	.st24{fill:#BF2126;}
</style>
  <svg:g inkscape:groupmode="layer" id="Torso_Unnatural_straps" inkscape:label="Torso_Unnatural_straps" style="display:inline">
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 501.152,204.07 C 500.44,208.762 504.877,212.166 510.374,215.305 C 523.664,215.126 537.25,213.091 550.54,206.278" id="path9218" inkscape:connector-curvature="0" sodipodi:nodetypes="ccc"/>
	<svg:path id="path9222" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" d="M 496.678,465.98 L 482.188,407.3 L 491.521,353.918 L 491.181,281.745 L 510.374,215.305 L 528.877,283.779 L 512.809,320.263 L 498.229,354.208 L 482.188,407.3 L 477.335,354.779 L 462.265,311.869 L 468.744,277.264 L 510.374,215.305" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc"/>
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 468.581,355.606 L 477.335,354.779 L 491.521,353.918 L 498.229,354.208 L 535.693,361.984" id="path9224" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
	<svg:path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 465.026,377.931 C 472.614,387.409 477.095,393.328 482.188,407.3 C 495.417,392.256 523.809,387.614 542.329,378.524" id="path9226" inkscape:connector-curvature="0" sodipodi:nodetypes="ccc"/>
	<svg:path id="path4809" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 586.895,273.468 L 558.608,283.791 L 528.877,283.779 L 491.181,281.745 L 468.744,277.264 L 459.884,274.615" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccc"/>
  </svg:g>
</svg>


path: resources/vector/test ui.svg


code:
#!/bin/bash
if [ ! -d ".git" ]; then
	#not running in git repo, so can't use git commands :-)
	echo "No .git repo found - skipping sanity checks"
	exit 0
fi

WARNING='\033[93m'

myprint() {
	while read -r data; do
		echo -n -e "[$1]$WARNING"
		echo "$data"
	done
}

GREP="git grep -n --color"

# Check for accidental assignment.  e.g.:   <<if $foo = "hello">>
$GREP "<<[ ]*if[^>=]*[^><\!=]=[^=][^>]*>>" -- 'src/*' | myprint "AccidentalAssignmentInIf"
# Check for accidental assignment.  e.g.:   <<elseif $foo = "hello">>
$GREP "<<[ ]*elseif[^>=]*[^><\!=]=[^=][^>]*>>" -- 'src/*' | myprint "AccidentalAssignmentInElseIf"
# Check for missing ".  e.g.:   <<if $foo == "hello>>
$GREP "<<[^\"<>]*\"[^\"<>]*>>" -- 'src/*' | myprint "MissingSpeechMark"
# Check for missing ".  e.g.:   <<if $foo = "hello)
$GREP -e "<<[^\"<>]*\([^\"<>]*\"[^><\"]*\"\| [<>] \)*\"\([^\"<>]*\"[^><\"]*\"\| [<>] \)*\([^\"<>]\| [<>] \)*>>" --and --not -e "*[^']*" -- 'src/*' | myprint "MissingSpeechMark2"
# Check for colors like: @@color:red   - should be @@.red
$GREP -e "@@color:" --and --not -e "@@color:rgb([0-9 ]\+,[0-9 ]\+,[0-9 ]\+)" -- "src/*" | myprint "UseCSSColors"
# Check for missing $ in activeSlave or PC
$GREP "<<[ ]*[^\$><_\[]*\(activeSlave\|PC\)[.]" -- "src/*" | myprint "MissingDollar"
# Check for closing bracket without opening bracket.  e.g.:  <<if foo)>>	  (but  <<case "foo")>>   is valid, so ignore those
$GREP -e "<<[ a-zA-Z]\+\([^()<>]\|[^()<>][<>][^()<>]\)*)" --and --not -e "<< *case" -- "src/*" | myprint "MissingOpeningBracket"
# Check for opening bracket without closing bracket.  e.g.:  <<if (foo>>
$GREP -e "<<[ a-zA-Z]\([^<>]\|[^<>][<>][^<>]\)\+(\([^()<>]\|[^<>()][<>][^<>()]\|([^<>()]*])\)*>>" -- "src/*" | myprint "MissingClosingBracket"
# Check for two closing brackets but one opening bracket.  e.g.:  <<if (foo))>>
$GREP -e "<<[ a-zA-Z]\+[^()<>]*([^()]*)[^()]*)[^()<>]*>>" -- "src/*" | myprint "MissingOpeningBracket2"
# Check for one closing bracket but two opening brackets.  e.g.:  <<if ((foo)>>
$GREP -e "<<[ a-zA-Z]\+[^()<>]*([^()]*([^()]*)[^()<>]*>>" -- "src/*" | myprint "MissingClosingBracket2"
$GREP -e "<<.*[(][^<>)]*[(][^<>)]*)\?[^<>)]*>>" -- "src/*" | myprint "MissingClosingBracket3"
# Check for too many >>>.  e.g.: <</if>>>
$GREP "<<[^<>]*[<>]\?[^<>]*>>>" -- "src/*.tw" | myprint "TooManyAngleBrackets"
# Check for wrong capitalization on 'activeslave' and other common typos
$GREP -e "\$act" --and --not -e "\$\(activeSlave\|activeChild\|activeArcology\|activeStandard\|activeOrgan\|activeLimbs\|activeUnits\|activeCanine\|activeHooved\|activeFeline\|activeLurcher\)" -- "src/*" | myprint "WrongCapitilization"
# Check for strange spaces e.g.  $slaves[$i]. lips
$GREP "\$slaves\[\$i\]\. " -- 'src/*' | myprint "MissingPropertyAfterSlaves"
# Check using refreshmentType instead of refreshment
$GREP "\$PC.refreshmentType[^ =]" -- 'src/*' | grep -v src/events/intro/introSummary.tw | myprint "ShouldBeRefreshment"
# Check, e.g.  <<else $foo==4
$GREP "<<else >\?[^>]" -- 'src/*' | myprint "ShouldBeElseIf"
# Check, e.g., =to
$GREP "=to" -- 'src/*' | myprint "EqualAndTo"
# Check doing  $slaves.foo instead of $slaves[i].foo
$GREP -e "[$]slaves[.]" --and --not -e '[$]slaves[.]\(length\|random\|map\|filter\|deleteAt\|push\|find\|includes\|delete\|forEach\)' -- 'src/*' | myprint "MissingSlavesIndex"
# Try to check for accidentally mixing slaves[] and activeSlave.  This can have a lot of false matches, but has caught a lot of bugs so it's worth the pain
$GREP -e "activeSlave[.]" --and -e "slaves\[..\?\][.]" --and --not -e '[.]ID' --and --not -e 'slaves\[..\?\][.]\(slaveName\|slaveSurname\|actualAge\|relation\|assignment\|age\|devotion\|trust\|vagina\|mother\|father\|training\)' -- 'src/*' | myprint "MaybeAccidentalMixingOfSlavesAndActiveSlave"
# Check, e.g.  <<set foo == 4>>
$GREP "<<set[^{>=]*==" -- 'src/*' | myprint "DoubleEqualsInSet"
# Check for, e.g   <<if slaves[foo]>>
$GREP "<<\([^>]\|[^>]>[^>]\)*[^$]slaves\[" -- 'src/*' | myprint "MissingDollar"
# Check for missing $ or _ in variable name:
$GREP -e "<<[a-zA-Z]\([^>\"]\|[^>]>[^>]\|\"[^\"]*\"\)* [a-zA-Z]\+ * =" -- src/*.tw | myprint "MissingDollar2"
# Check for missing command, e.g.  <<foo =
$GREP -e "<<[a-zA-Z]* = *" -- src/*.tw | myprint "BadCommand"
# Check for duplicate words, e.g. with with
$GREP -e " \(\b[a-zA-Z][a-zA-Z]\+\) \1\b " --and --not -e " her her " --and --not -e " you you " --and --not -e " New New " --and --not -e "Slave Slave " --and --not -e " that that " --and --not -e " in in " --and --not -e " is is " -- 'src/*' | myprint "Duplicate words"
# Check for obsolete SugarCube macros
$GREP -E "<<display |<<click|<<.*\.contains" -- src/*.tw | myprint "ObsoleteMacro"
# Check for double articles
$GREP -E "\Wa an\W" -- src/*.tw | myprint "DoubleArticle"
# Check for incorrect articles
$GREP -i -E "\Wa (a|e|i|o|u)." -- src/*.tw | grep -a -i -vE "\Wa (un|eu|us|ut|on|ur|in)." | grep -a -i -vE "(&|<<s>>|UM)." | myprint "IncorrectArticle"
$GREP -i -E "\Wan (b|c|d|f|g|j|k|l|m|n|p|q|r|s|t|v|w|x|y|z)\w." -- src/*.tw | grep -a -i -vE "[A-Z]{3}" | myprint "IncorrectArticle"
# Check for $ sign mid-word
$GREP -i "\w$\w" -- src/*.tw | myprint "VarSignMidWord"
# check for $ sign at beginning of macro
$GREP '<<\s*\$' -- 'src/*' | myprint "VarSignAtMacroStart"
# check our custom option macro is either options,option,optionlt,optionlte,optiongt,optiongte,optiondefault,optionstyle,optionif
$GREP -e '<<option' --and --not -e "<<option\(\|s\|lt\|lte\|gt\|gte\|default\|style\|if\)[ >]" -- 'src/*' | myprint "OptionUnrecognized"
# check our custom option macro is: <<option variable "somestring"
$GREP -e "<<option[lg]te\? " --and --not -e "<<option[lg]te\?\s\+-\?[0-9]\+\s\+-\?[0-9]\+\s\+[\'\"].*[\'\"]" -- 'src/*' | grep -v src/js | myprint "OptionBadArguments1"
$GREP -e "<<optiondefault " --and --not -e "<<optiondefault\s\+\(-\?[0-9]\+\|[\'\"].*[\'\"]\|false\|true\)\s\+[\'\"].*[\'\"]" -- 'src/*' | grep -v src/js | myprint "OptionBadArguments2"
$GREP -e "<<option\([lg]t\?\|default\) *>" -- 'src/*' | grep -v src/js | myprint "OptionBadArguments3"
#$GREP -e "<<option " --and --not -e "<<option\s\+\(-\?[0-9]\+\|[\'\"].*[\'\"]\|false\|true\)\s\+[\`\'\"].*[\'\"\`]" -- 'src/*' | grep -v src/js | myprint "OptionBadArguments4" # too many false positives
$GREP -e "<<if def [^(>]*[&|]" -- 'src/*' | myprint "AddBracketsAroundDef2"
# check for missing ; before statement
$GREP 'if $ ' -- 'src/*' | myprint "Missing ; before statement"
$GREP 'elseif $ ' -- 'src/*' | myprint "Missing ; before statement"
# Check for an unrecognized letter before >>
$GREP "[^]a-zA-Z0-9 \")}'+-\*\`] *>>" -- 'src/*' | myprint "StrangeCharacterAtEndOfCommand"
# Check for a . inside a <<>>
$GREP "<<[a-zA-Z]\([^\"'>]\|[^\"'>]>[^\"'>]\)*[a-zA-Z][.][^a-zA-Z]" | myprint "StrangeCharacterAfterDot"
# Check for @@.  instead of .@@
$GREP -E "@@(\.|,|;|:)\s" -- src/*.tw | myprint "WrongSelectorPunctuation"
$GREP "@@[a-z]\+;" -- 'src/*' | myprint "SelectorMissingDot"
# Check for .  instead of .
$GREP -E "(\.|,|;|:)\s" -- src/*.js | myprint "WrongSelectorPunctuation"
# Check for missing whitespace between operators
#$GREP -E "\(.(\+|\-|\*|\/|\=)." -- src/*.js :^src/001-lib/Jquery.js,^src/js/dTree.min.js,^devTools/tweeGo/storyFormats/sugarcube-2/format.js,^src/001-lib/mousetrap.js | myprint "MissingWhitespace"		disabled until I can figure out how to exclude files
# Check for @@ selector instead of  selector
$GREP "@@\." -- src/*.js | myprint "WrongSelectorUsed"
# Check for JSdoc inside function declaration
#$GREP -e ".\=.\/\*\*" --or -e "slave\s\*\/" -- src/*.js --exclude 'src/interaction/main/mainLinks.js' | myprint "WrongJSdocFormat"	# this --exclude doesn't work # too many false positives
# Check for missing whitespace at end of /**/ style comments
#$GREP "\S\*\/" -- src/* --exclude 'src/001-lib/jquery/Jquery.js' | myprint "MissingWhitespace"		disabled until I can figure out to exclude files
# Check for var instead of let or const
#$GREP "var\s" -- src/*.js | myprint "UseLetOrConst"	disabled until I can figure out how to exclude certain files
# Check for non lethal or non-lethal instead of nonlethal
$GREP -i "non.lethal" -- 'src/*' | myprint "ShouldBeNonlethal"
# Check for missing quotation marks around selectors
#$GREP "span class=[^\"]" -- src/*.js --exclude 'src/001-lib/Jquery/Jquery.js' | myprint "MissingQuotes" disabled until I can figure out how to exclude files

(
	cd src/ || exit
	$GREP "\$\(PC\|activeSlave\|slaves\|tanks\)[.][^a-zA-Z]" | myprint "UnexpectedCharAfterDot"
)

# Check that all the tags are properly opened and closed & a lot of other stuff
java -jar devTools/javaSanityCheck/SanityCheck.jar


code:
# Tool(s) for hacking saved games

The script `fc_edit_save.py` can be used to read or write FC games saved with the "Save to Disk..." option.
It can convert the compressed files (usually named `free-cities-YYYYMMDD-HHMMSS.save`) to or from JSON format,
view or modify some variables, search for slaves matching some criteria to view or modify them, etc.

## Dependencies

The script `fc_edit_save.py` requires Python version 3.6 or later.

In addition, it uses a small module called `lzstring`, available via [PyPI](https://pypi.org/project/lzstring/).
If you do not have it yet, you can install it with `pip3 install lzstring` or simply `pip install lzstring` if
your default version of Python is already Python 3.x.  You can also install the module manually from PyPI
without using `pip`, but then you are on your own for copying the files in the right locations.

## Usage

To view the help message summarizing the command-line arguments, try:
```
./fc_edit_save.py --help
```

To view a longer help message including details for each command and a list of examples, try:
```
./fc_edit_save.py --long-help
```

The basic usage consists of:

 * reading an input file (compressed `*.save` file with the option `-i`, or uncompressed JSON file with the
   option `-I`),

 * optionally modifying it with various commands,

 * then saving the result in some output file (compressed `*.save` file with the option `-o`, or uncompressed
   JSON file with the option `-O`).

If the options `-i`/`-I` or `-o`/`-O` are not used, then the standard input and standard output will be used, which
allows this script to be used easily in a pipe including other commands.  If the input is a file, then the option
`-A` can also be used instead of `-o`/`-O` to set the name of the output file automatically.  Try `--help` and
`--long-help` for more details.

## Examples

The following examples assume that you already have a saved game in the file `free-cities-20200401-123456.save`.

To convert a compressed FC game file to a human-readable JSON file:
```
./fc_edit_save.py -i free-cities-20200104-123456.save -p -O free-cities-20200104-123456.json
```

To convert a JSON file to a compressed FC game file:
```
./fc_edit_save.py -I free-cities-20200104-123456.json -o free-cities-20200104-123456.save
```

To display the names and current assignments of all smart slaves (with more than 50 in intelligence):
```
./fc_edit_save.py -i free-cities-20200104-123456.save -p --get-slaves 'intelligence>50' 'name,assignment'
```

To ensure that all your slaves have at least DD-cup boobs and change the hair of Miss Lily at random:
```
./fc_edit_save.py -i free-cities-20200104-123456.save -A --set-slaves all 'boobs=atleast:900' --set-slaves 'Miss Lily' randomhair -v
```
Note that the option `-A` in this example will save the results in the file `free-cities-20200104-123456-cheat.save`.
The option `-v` will show the changes that are applied to all slaves.

For more examples, try `--long-help`.