major work to sounds and reloading mechanics
This commit is contained in:
parent
b972ee78b8
commit
8585180634
23
TODO.txt
23
TODO.txt
@ -3,11 +3,18 @@
|
||||
|
||||
|
||||
|
||||
( ) add audio
|
||||
( ) add config
|
||||
(~) add audio
|
||||
(x) sfx system
|
||||
(x) did signifficant work on it
|
||||
(x) firing sound effects
|
||||
( ) reload sound effects
|
||||
( ) firemode sound effects
|
||||
(~) add config
|
||||
(x) add a table for config storage, some settings
|
||||
( ) integrate with minetest settings
|
||||
(x) fix crash when switching from a gun into a gun with a sprite_scope
|
||||
(x) add infinite ammo privelage and quick command
|
||||
( ) privilege not directly tied to infinite ammo, fix without breaking performance?
|
||||
(x) privilege not directly tied to infinite ammo, fix without breaking performance?
|
||||
(x) fix animation rotation offset not displaying the correct frame
|
||||
-was a problem with MTUL, changes push :D
|
||||
( ) add entity scopes (for holo sights etc)
|
||||
@ -17,7 +24,7 @@
|
||||
( ) fractional
|
||||
( ) flat (magless)
|
||||
( ) fractional clip
|
||||
( ) (for 5.9) make infinite ammo priv to rely on on_grant and on_revoke callback for runtime changes (broken as of 5.8)
|
||||
( ) (for 5.9) make infinite ammo priv to rely on on_grant and on_revoke callback for runtime changes (cannot be done as broken in 5.8)
|
||||
( ) (5.9) POTENTIALLY make models use new PR that allows bone offsets to be disabled
|
||||
-I'd probably have to modify models at loadtime to have an eye and hipfire bone? Probably easier then current system though.
|
||||
( ) Fix HORRIBLE namespace violation in misc_helpers.lua. Also migrate features to MTUL libraries
|
||||
@ -42,5 +49,9 @@ documentation
|
||||
( ) Bullet_ray
|
||||
|
||||
|
||||
( ) play_sound.lua
|
||||
( ) misc_helpers.lua
|
||||
(x) play_sound.lua
|
||||
(~) misc_helpers.lua
|
||||
(x) weighted randoms
|
||||
( ) unique ID
|
||||
( ) table helpers
|
||||
( ) openGL/irrlicht relative dir projection
|
@ -26,7 +26,7 @@ end
|
||||
function Guns4d.ammo.register_bullet(def)
|
||||
assert(def.itemstring, "no itemstring")
|
||||
assert(minetest.registered_items[def.itemstring], "no item '"..def.itemstring.."' found. Must be a registered item (check dependencies?)")
|
||||
Guns4d.ammo.registered_bullets[def.itemstring] = table.fill(Default_bullet, def)
|
||||
Guns4d.ammo.registered_bullets[def.itemstring] = Guns4d.table.fill(Default_bullet, def)
|
||||
end
|
||||
function Guns4d.ammo.initialize_mag_data(itemstack, meta)
|
||||
meta = meta or itemstack:get_meta()
|
||||
@ -45,9 +45,8 @@ function Guns4d.ammo.update_mag(def, itemstack, meta)
|
||||
count = count + v
|
||||
end
|
||||
local new_wear = max_wear-(max_wear*count/def.capacity)
|
||||
--itemstack:set_wear(math.clamp(new_wear, 1, max_wear-1))
|
||||
--itemstack:set_wear(Guns4d.math.clamp(new_wear, 1, max_wear-1))
|
||||
meta:set_int("guns4d_total_bullets", count)
|
||||
meta:set_string("guns4d_next_bullet", current_bullet)
|
||||
if count > 0 then
|
||||
meta:set_string("count_meta", tostring(count).."/"..def.capacity)
|
||||
else
|
||||
@ -57,7 +56,7 @@ function Guns4d.ammo.update_mag(def, itemstack, meta)
|
||||
end
|
||||
|
||||
function Guns4d.ammo.register_magazine(def)
|
||||
def = table.fill(Default_mag, def)
|
||||
def = Guns4d.table.fill(Default_mag, def)
|
||||
assert(def.accepted_bullets, "missing property def.accepted_bullets. Need specified bullets to allow for loading")
|
||||
assert(def.itemstring, "missing item name")
|
||||
def.accepted_bullets_set = {} --this table is a "lookup" table, I didn't go to college so I have no idea
|
||||
|
77
autogen_docs/index.html
Normal file
77
autogen_docs/index.html
Normal file
@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>4dguns documentation</title>
|
||||
<link rel="stylesheet" href="ldoc_new.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
<br/>
|
||||
<h1>4dguns</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Scripts</h2>
|
||||
<ul class="nowrap">
|
||||
<li><a href="scripts/misc_helpers.html">misc_helpers</a></li>
|
||||
<li><a href="scripts/play_sound.html">play_sound</a></li>
|
||||
</ul>
|
||||
<h2>Topics</h2>
|
||||
<ul class="">
|
||||
<li><a href="topics/readme.md.html">readme</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
|
||||
<h2>THEE ultimate 3d gun library.</h2>
|
||||
|
||||
<h2>Scripts</h2>
|
||||
<table class="module_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="scripts/misc_helpers.html">misc_helpers</a></td>
|
||||
<td class="summary">misc.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="scripts/play_sound.html">play_sound</a></td>
|
||||
<td class="summary">implements tools for quickly playing audio.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2>Topics</h2>
|
||||
<table class="module_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="topics/readme.md.html">readme.md</a></td>
|
||||
<td class="summary"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
|
||||
<i style="float:right;">Last updated 2024-01-19 14:08:01 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
290
autogen_docs/ldoc_new.css
Normal file
290
autogen_docs/ldoc_new.css
Normal file
@ -0,0 +1,290 @@
|
||||
body {
|
||||
color: #47555c;
|
||||
font-size: 16px;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
margin: 0;
|
||||
background: #eff4ff;
|
||||
}
|
||||
|
||||
a:link { color: #008fee; }
|
||||
a:visited { color: #008fee; }
|
||||
a:hover { color: #22a7ff; }
|
||||
|
||||
h1 { font-size:26px; font-weight: normal; }
|
||||
h2 { font-size:22px; font-weight: normal; }
|
||||
h3 { font-size:18px; font-weight: normal; }
|
||||
h4 { font-size:16px; font-weight: bold; }
|
||||
|
||||
hr {
|
||||
height: 1px;
|
||||
background: #c1cce4;
|
||||
border: 0px;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
code, tt {
|
||||
font-family: monospace;
|
||||
}
|
||||
span.parameter {
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
color: rgb(99, 115, 131);
|
||||
}
|
||||
span.parameter:after {
|
||||
content:":";
|
||||
}
|
||||
span.types:before {
|
||||
content:"(";
|
||||
}
|
||||
span.types:after {
|
||||
content:")";
|
||||
}
|
||||
.type {
|
||||
font-weight: bold; font-style:italic
|
||||
}
|
||||
|
||||
p.name {
|
||||
font-family: "Andale Mono", monospace;
|
||||
}
|
||||
|
||||
#navigation {
|
||||
float: left;
|
||||
background-color: white;
|
||||
border-right: 1px solid #d3dbec;
|
||||
border-bottom: 1px solid #d3dbec;
|
||||
|
||||
width: 14em;
|
||||
vertical-align: top;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
#navigation br {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#navigation h1 {
|
||||
background-color: white;
|
||||
border-bottom: 1px solid #d3dbec;
|
||||
padding: 15px;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
#navigation h2 {
|
||||
font-size: 18px;
|
||||
background-color: white;
|
||||
border-bottom: 1px solid #d3dbec;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
#content h1 {
|
||||
background-color: #2c3e67;
|
||||
color: white;
|
||||
padding: 15px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#content h2 {
|
||||
background-color: #6c7ea7;
|
||||
color: white;
|
||||
padding: 15px;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
#content h2 a {
|
||||
background-color: #6c7ea7;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#content h2 a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#content h3 {
|
||||
font-style: italic;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 4px;
|
||||
margin-right: 15px;
|
||||
margin-left: 15px;
|
||||
margin-bottom: 5px;
|
||||
border-bottom: solid 1px #bcd;
|
||||
}
|
||||
|
||||
#content h4 {
|
||||
margin-right: 15px;
|
||||
margin-left: 15px;
|
||||
border-bottom: solid 1px #bcd;
|
||||
}
|
||||
|
||||
#content pre {
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: rgb(50, 55, 68);
|
||||
color: white;
|
||||
border-radius: 3px;
|
||||
/* border: 1px solid #C0C0C0; /* silver */
|
||||
padding: 15px;
|
||||
overflow: auto;
|
||||
font-family: "Andale Mono", monospace;
|
||||
}
|
||||
|
||||
#content ul pre.example {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
table.index {
|
||||
/* border: 1px #00007f; */
|
||||
}
|
||||
table.index td { text-align: left; vertical-align: top; }
|
||||
|
||||
#navigation ul
|
||||
{
|
||||
font-size:1em;
|
||||
list-style-type: none;
|
||||
margin: 1px 1px 10px 1px;
|
||||
}
|
||||
|
||||
#navigation li {
|
||||
text-indent: -1em;
|
||||
display: block;
|
||||
margin: 3px 0px 0px 22px;
|
||||
}
|
||||
|
||||
#navigation li li a {
|
||||
margin: 0px 3px 0px -1em;
|
||||
}
|
||||
|
||||
#content {
|
||||
margin-left: 14em;
|
||||
}
|
||||
|
||||
#content p {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
#content table {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
#content p, #content table, #content ol, #content ul, #content dl {
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
#about {
|
||||
padding: 15px;
|
||||
padding-left: 16em;
|
||||
background-color: white;
|
||||
border-top: 1px solid #d3dbec;
|
||||
border-bottom: 1px solid #d3dbec;
|
||||
}
|
||||
|
||||
table.module_list, table.function_list {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #cccccc;
|
||||
border-collapse: collapse;
|
||||
margin: 15px;
|
||||
}
|
||||
table.module_list td, table.function_list td {
|
||||
border-width: 1px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
border: solid 1px rgb(193, 204, 228);
|
||||
}
|
||||
table.module_list td.name, table.function_list td.name {
|
||||
background-color: white; min-width: 200px; border-right-width: 0px;
|
||||
}
|
||||
table.module_list td.summary, table.function_list td.summary {
|
||||
background-color: white; width: 100%; border-left-width: 0px;
|
||||
}
|
||||
|
||||
dl.function {
|
||||
margin-right: 15px;
|
||||
margin-left: 15px;
|
||||
border-bottom: solid 1px rgb(193, 204, 228);
|
||||
border-left: solid 1px rgb(193, 204, 228);
|
||||
border-right: solid 1px rgb(193, 204, 228);
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
dl.function dt {
|
||||
color: rgb(99, 123, 188);
|
||||
font-family: monospace;
|
||||
border-top: solid 1px rgb(193, 204, 228);
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
dl.function dd {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#content dl.function dd h3 {
|
||||
margin-top: 0px;
|
||||
margin-left: 0px;
|
||||
padding-left: 0px;
|
||||
font-size: 16px;
|
||||
color: rgb(128, 128, 128);
|
||||
border-bottom: solid 1px #def;
|
||||
}
|
||||
|
||||
#content dl.function dd ul, #content dl.function dd ol {
|
||||
padding: 0px;
|
||||
padding-left: 15px;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
ul.nowrap {
|
||||
overflow:auto;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
.section-description {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
/* stop sublists from having initial vertical space */
|
||||
ul ul { margin-top: 0px; }
|
||||
ol ul { margin-top: 0px; }
|
||||
ol ol { margin-top: 0px; }
|
||||
ul ol { margin-top: 0px; }
|
||||
|
||||
/* make the target distinct; helps when we're navigating to a function */
|
||||
a:target + * {
|
||||
background-color: #FF9;
|
||||
}
|
||||
|
||||
|
||||
/* styles for prettification of source */
|
||||
pre .comment { color: #bbccaa; }
|
||||
pre .constant { color: #a8660d; }
|
||||
pre .escape { color: #844631; }
|
||||
pre .keyword { color: #ffc090; font-weight: bold; }
|
||||
pre .library { color: #0e7c6b; }
|
||||
pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; }
|
||||
pre .string { color: #8080ff; }
|
||||
pre .number { color: #f8660d; }
|
||||
pre .operator { color: #2239a8; font-weight: bold; }
|
||||
pre .preprocessor, pre .prepro { color: #a33243; }
|
||||
pre .global { color: #c040c0; }
|
||||
pre .user-keyword { color: #800080; }
|
||||
pre .prompt { color: #558817; }
|
||||
pre .url { color: #272fc2; text-decoration: underline; }
|
73
autogen_docs/modules/misc_helpers.html
Normal file
73
autogen_docs/modules/misc_helpers.html
Normal file
@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>4dguns documentation</title>
|
||||
<link rel="stylesheet" href="../ldoc_new.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
<br/>
|
||||
<h1>4dguns</h1>
|
||||
|
||||
|
||||
<ul>
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<h2>Modules</h2>
|
||||
<ul class="nowrap">
|
||||
<li><strong>misc_helpers</strong></li>
|
||||
</ul>
|
||||
<h2>Scripts</h2>
|
||||
<ul class="nowrap">
|
||||
<li><a href="../scripts/play_sound.html">play_sound</a></li>
|
||||
</ul>
|
||||
<h2>Topics</h2>
|
||||
<ul class="">
|
||||
<li><a href="../topics/readme.md.html">readme</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>misc_helpers</code></h1>
|
||||
<p>picks a random index, with odds based on it's value.</p>
|
||||
<p> Returns the index of the selected.</p>
|
||||
|
||||
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
|
||||
<i style="float:right;">Last updated 2024-01-16 17:00:50 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
112
autogen_docs/scripts/misc_helper.html
Normal file
112
autogen_docs/scripts/misc_helper.html
Normal file
@ -0,0 +1,112 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>4dguns documentation</title>
|
||||
<link rel="stylesheet" href="../ldoc_new.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
<br/>
|
||||
<h1>4dguns</h1>
|
||||
|
||||
|
||||
<ul>
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Contents</h2>
|
||||
<ul>
|
||||
<li><a href="#Functions">Functions</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Scripts</h2>
|
||||
<ul class="nowrap">
|
||||
<li><strong>misc_helper</strong></li>
|
||||
<li><a href="../scripts/play_sound.html">play_sound</a></li>
|
||||
</ul>
|
||||
<h2>Topics</h2>
|
||||
<ul class="">
|
||||
<li><a href="../topics/readme.md.html">readme</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Script <code>misc_helper</code></h1>
|
||||
<p>misc.</p>
|
||||
<p> common tools for 4dguns</p>
|
||||
|
||||
|
||||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#Guns4d.math.weighted_randoms">Guns4d.math.weighted_randoms (tbl)</a></td>
|
||||
<td class="summary">picks a random index, with odds based on it's value.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
|
||||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "Guns4d.math.weighted_randoms"></a>
|
||||
<strong>Guns4d.math.weighted_randoms (tbl)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
picks a random index, with odds based on it's value. Returns the index of the selected.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">tbl</span>
|
||||
|
||||
<p> a table containing weights, example</p>
|
||||
<pre><code> {
|
||||
["sound"] = 999, --999 in 1000 chance this plays
|
||||
["rare_sound"] = 1 --1 in 1000 chance this plays
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
|
||||
<i style="float:right;">Last updated 2024-01-16 17:04:01 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
115
autogen_docs/scripts/misc_helpers.html
Normal file
115
autogen_docs/scripts/misc_helpers.html
Normal file
@ -0,0 +1,115 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>4dguns documentation</title>
|
||||
<link rel="stylesheet" href="../ldoc_new.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
<br/>
|
||||
<h1>4dguns</h1>
|
||||
|
||||
|
||||
<ul>
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Contents</h2>
|
||||
<ul>
|
||||
<li><a href="#math_helpers">math helpers </a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Scripts</h2>
|
||||
<ul class="nowrap">
|
||||
<li><strong>misc_helpers</strong></li>
|
||||
<li><a href="../scripts/play_sound.html">play_sound</a></li>
|
||||
</ul>
|
||||
<h2>Topics</h2>
|
||||
<ul class="">
|
||||
<li><a href="../topics/readme.md.html">readme</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Script <code>misc_helpers</code></h1>
|
||||
<p>misc.</p>
|
||||
<p> common tools for 4dguns</p>
|
||||
|
||||
|
||||
<h2><a href="#math_helpers">math helpers </a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#weighted_randoms">weighted_randoms (tbl)</a></td>
|
||||
<td class="summary">picks a random index, with odds based on it's value.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
<h2 class="section-header has-description"><a name="math_helpers"></a>math helpers </h2>
|
||||
|
||||
<div class="section-description">
|
||||
in guns4d.math
|
||||
</div>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "weighted_randoms"></a>
|
||||
<strong>weighted_randoms (tbl)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
picks a random index, with odds based on it's value. Returns the index of the selected.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">tbl</span>
|
||||
|
||||
<p> a table containing weights, example</p>
|
||||
<pre><code> {
|
||||
["sound"] = 999, --999 in 1000 chance this is chosen
|
||||
["rare_sound"] = 1 --1 in 1000 chance this is chosen
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
|
||||
<i style="float:right;">Last updated 2024-01-19 14:08:01 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
162
autogen_docs/scripts/play_sound.html
Normal file
162
autogen_docs/scripts/play_sound.html
Normal file
@ -0,0 +1,162 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>4dguns documentation</title>
|
||||
<link rel="stylesheet" href="../ldoc_new.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
<br/>
|
||||
<h1>4dguns</h1>
|
||||
|
||||
|
||||
<ul>
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Contents</h2>
|
||||
<ul>
|
||||
<li><a href="#Functions">Functions</a></li>
|
||||
<li><a href="#Tables">Tables</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Scripts</h2>
|
||||
<ul class="nowrap">
|
||||
<li><a href="../scripts/misc_helpers.html">misc_helpers</a></li>
|
||||
<li><strong>play_sound</strong></li>
|
||||
</ul>
|
||||
<h2>Topics</h2>
|
||||
<ul class="">
|
||||
<li><a href="../topics/readme.md.html">readme</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Script <code>play_sound</code></h1>
|
||||
<p>implements tools for quickly playing audio.</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#Guns4d.play_sound">Guns4d.play_sound (sound_specs)</a></td>
|
||||
<td class="summary">allows you to play one or more sounds with more complex features, so sounds can be easily coded for guns without the need for functions.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2><a href="#Tables">Tables</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#guns4d_soundspec">guns4d_soundspec</a></td>
|
||||
<td class="summary">defines a sound.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
|
||||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "Guns4d.play_sound"></a>
|
||||
<strong>Guns4d.play_sound (sound_specs)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
allows you to play one or more sounds with more complex features, so sounds can be easily coded for guns without the need for functions.
|
||||
WARNING: this function modifies the tables passed to it, use <code>Guns4d.table.shallow_copy()</code> for guns4d_soundspecs
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">sound_specs</span>
|
||||
|
||||
<p> a <a href="../scripts/play_sound.html#guns4d_soundspec">guns4d_soundspec</a> or a list of <a href="../scripts/play_sound.html#guns4d_soundspec">guns4d_soundspec</a>s indexed my number. Also allows for shared fields. Example:</p>
|
||||
<pre><code> {
|
||||
to_player = "singeplayer",
|
||||
min_distance = 100, --soundspec_to_play1 & soundspec_to_play2 share this parameter (as well as the to_player)
|
||||
soundspec_to_play1,
|
||||
soundspec_to_play2
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
out a list of Minetest sound handles [insert link] (in the order they came)
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<h2 class="section-header "><a name="Tables"></a>Tables</h2>
|
||||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "guns4d_soundspec"></a>
|
||||
<strong>guns4d_soundspec</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
defines a sound.
|
||||
This is passed to <code>minetest.sound_play</code> as a <a href="https://github.com/minetest/minetest/blob/master/doc/lua_api.md#sound-parameter-table"> sound parameter table</a>
|
||||
however has the following changed or guns4d specific parameters.
|
||||
|
||||
|
||||
<h3>Fields:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">min_hear_distance</span>
|
||||
this is useful if you wish to play a sound which has a "far" sound, such as distant gunshots. incompatible <code>with to_player</code>
|
||||
</li>
|
||||
<li><span class="parameter">sounds</span>
|
||||
a <a href="../scripts/misc_helpers.html#weighted_randoms"> weighted_randoms table</a> the output will overwrite the <code>sound</code> field.
|
||||
</li>
|
||||
<li><span class="parameter">to_player</span>
|
||||
4dguns changes <code>to_player</code> so it only plays positionless audio (as it is only intended for first person audio)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
|
||||
<i style="float:right;">Last updated 2024-01-19 14:08:01 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
63
autogen_docs/topics/readme.md.html
Normal file
63
autogen_docs/topics/readme.md.html
Normal file
@ -0,0 +1,63 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>4dguns documentation</title>
|
||||
<link rel="stylesheet" href="../ldoc_new.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
<br/>
|
||||
<h1>4dguns</h1>
|
||||
|
||||
|
||||
<ul>
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<h2>Topics</h2>
|
||||
<ul class="">
|
||||
<li><strong>readme</strong></li>
|
||||
</ul>
|
||||
<h2>Scripts</h2>
|
||||
<ul class="nowrap">
|
||||
<li><a href="../scripts/misc_helpers.html">misc_helpers</a></li>
|
||||
<li><a href="../scripts/play_sound.html">play_sound</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
|
||||
<h1>4dguns</h1>
|
||||
<p>3dguns remastered. Currently a work in progress that is updating steadily (kind of).</p>
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
|
||||
<i style="float:right;">Last updated 2024-01-19 14:08:01 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
@ -34,6 +34,7 @@ function Ammo_handler:update_meta(bullets)
|
||||
meta:set_string("guns4d_loaded_bullets", bullets or minetest.serialize(self.ammo.loaded_bullets))
|
||||
meta:set_int("guns4d_total_bullets", self.ammo.total_bullets)
|
||||
meta:set_string("guns4d_next_bullet", self.ammo.next_bullet)
|
||||
self.ammo.magazine_psuedo_empty = false
|
||||
if self.gun.ammo_handler then --if it's a first occourance it cannot work.
|
||||
self.gun:update_image_and_text_meta(meta)
|
||||
end
|
||||
@ -45,7 +46,7 @@ function Ammo_handler:spend_round()
|
||||
local bullet_spent = self.ammo.next_bullet
|
||||
local meta = self.gun.meta
|
||||
--subtract the bullet
|
||||
if self.ammo.total_bullets > 0 then
|
||||
if (self.ammo.total_bullets > 0) and (bullet_spent ~= "empty") then
|
||||
--only actually subtract the round if infinite_ammo is false.
|
||||
if not self.handler.infinite_ammo then
|
||||
self.ammo.loaded_bullets[bullet_spent] = self.ammo.loaded_bullets[bullet_spent]-1
|
||||
@ -54,7 +55,7 @@ function Ammo_handler:spend_round()
|
||||
end
|
||||
--set the new current bullet
|
||||
if next(self.ammo.loaded_bullets) then
|
||||
self.ammo.next_bullet = math.weighted_randoms(self.ammo.loaded_bullets)
|
||||
self.ammo.next_bullet = Guns4d.math.weighted_randoms(self.ammo.loaded_bullets)
|
||||
meta:set_string("guns4d_next_bullet", self.ammo.next_bullet)
|
||||
else
|
||||
self.ammo.next_bullet = "empty"
|
||||
@ -65,7 +66,10 @@ function Ammo_handler:spend_round()
|
||||
return bullet_spent
|
||||
end
|
||||
end
|
||||
function Ammo_handler:load_magazine()
|
||||
function Ammo_handler:close_bolt()
|
||||
self.ammo.next_bullet = Guns4d.math.weighted_randoms(self.ammo.loaded_bullets) or "empty"
|
||||
end
|
||||
function Ammo_handler:load_magazine(charge)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
local inv = self.inventory
|
||||
local magstack_index
|
||||
@ -108,7 +112,8 @@ function Ammo_handler:load_magazine()
|
||||
self.ammo.loaded_mag = magstack:get_name()
|
||||
self.ammo.loaded_bullets = minetest.deserialize(bullet_string)
|
||||
self.ammo.total_bullets = magstack_meta:get_int("guns4d_total_bullets")
|
||||
self.ammo.next_bullet = magstack_meta:get_string("guns4d_next_bullet")
|
||||
self.ammo.next_bullet = ((not charge) and "empty") or Guns4d.math.weighted_randoms(self.ammo.loaded_bullets)
|
||||
print(dump(self.ammo.next_bullet), dump(Guns4d.math.weighted_randoms(self.ammo.loaded_bullets)))
|
||||
self:update_meta()
|
||||
|
||||
inv:set_stack("main", magstack_index, "")
|
||||
@ -139,7 +144,12 @@ function Ammo_handler:can_load_magazine()
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--state will automatically set reset on update_meta()
|
||||
function Ammo_handler:set_unloading(bool)
|
||||
self.ammo.magazine_psuedo_empty = bool
|
||||
self.gun:update_image_and_text_meta()
|
||||
self.gun.player:set_wielded_item(self.gun.itemstack)
|
||||
end
|
||||
function Ammo_handler:unload_magazine(to_ground)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
if self.ammo.loaded_mag ~= "empty" then
|
||||
@ -150,7 +160,6 @@ function Ammo_handler:unload_magazine(to_ground)
|
||||
--set the mag's meta before updating ours and adding the item.
|
||||
magmeta:set_string("guns4d_loaded_bullets", gunmeta:get_string("guns4d_loaded_bullets"))
|
||||
magmeta:set_string("guns4d_total_bullets", gunmeta:get_string("guns4d_total_bullets"))
|
||||
magmeta:set_string("guns4d_next_bullet", gunmeta:get_string("guns4d_next_bullet"))
|
||||
magstack = Guns4d.ammo.update_mag(nil, magstack, magmeta)
|
||||
--throw it on the ground if to_ground is true
|
||||
local remaining
|
||||
|
@ -115,22 +115,20 @@ function ray:_iterate(initialized)
|
||||
local distance = vector.distance(self.pos, end_pos)
|
||||
if self.state == "free" then
|
||||
self.energy = self.energy-(distance*self.energy_dropoff)
|
||||
if distance ~= self.pos+(self.dir*self.range) then
|
||||
|
||||
if next_state == "transverse" then
|
||||
print(vector.distance(self.pos, end_pos), vector.distance(self.pos, self.pos+(self.dir*self.range)))
|
||||
self:bullet_hole(end_pos, end_normal)
|
||||
end
|
||||
else
|
||||
if self.history[#self.history].state == "free" then
|
||||
self:bullet_hole(self.pos, self.history[#self.history-1].normal)
|
||||
end
|
||||
--add exit holes
|
||||
if next_state == "free" then
|
||||
self:bullet_hole(end_pos, end_normal)
|
||||
end
|
||||
--calc penetration loss from traveling through the block
|
||||
local penetration_loss = distance*Guns4d.node_properties[self.last_node_name].mmRHA
|
||||
--calculate our energy loss based on the percentage of energy our penetration represents.
|
||||
self.energy = self.energy-((self.init_energy*self.energy_sharp_ratio)*(penetration_loss/self.sharp_penetration))
|
||||
end
|
||||
if self.state ~= self.next_state then
|
||||
|
||||
end
|
||||
--set values for next iteration.
|
||||
self.range = self.range-distance
|
||||
@ -187,11 +185,11 @@ function ray:hit_entity(object)
|
||||
|
||||
local resistance = object:get_armor_groups() -- support for different body parts is needed here, that's for... a later date, though.
|
||||
local sharp_pen = self.sharp_penetration-(self.sharp_penetration*(self.energy/self.init_energy)*self.energy_sharp_ratio)
|
||||
sharp_pen = math.clamp(sharp_pen - (resistance.guns4d_mmRHA or 0), 0, 65535)
|
||||
sharp_pen = Guns4d.math.clamp(sharp_pen - (resistance.guns4d_mmRHA or 0), 0, 65535)
|
||||
local converted_Pa = (resistance.guns4d_mmRHA or 0) * self.mmRHA_to_Pa_energy_ratio
|
||||
|
||||
local blunt_pen = converted_Pa+(self.blunt_penetration-(self.blunt_penetration*(self.energy/self.init_energy)*(1-self.energy_sharp_ratio)))
|
||||
blunt_pen = math.clamp(blunt_pen - (resistance.guns4d_Pa or 0), 0, 65535)
|
||||
blunt_pen = Guns4d.math.clamp(blunt_pen - (resistance.guns4d_Pa or 0), 0, 65535)
|
||||
self:apply_damage(object, sharp_pen, blunt_pen)
|
||||
|
||||
--raw damage first
|
||||
|
@ -35,40 +35,44 @@ function controls:update(dt)
|
||||
local pressed = self.player_pressed
|
||||
local call_queue = {} --so I need to have a "call" queue so I can tell the functions the names of other active controls (busy_list)
|
||||
local busy_list = self.busy_list or {} --list of controls that have their conditions met. Has to be reset at END of update, so on_use and on_secondary_use can be marked
|
||||
for i, control in pairs(self.controls) do
|
||||
if not (i=="on_use") and not (i=="on_secondary_use") then
|
||||
local def = control
|
||||
local data = control.data
|
||||
local conditions_met = true
|
||||
--check no conditions are false
|
||||
for _, key in pairs(control.conditions) do
|
||||
if not pressed[key] then conditions_met = false break end
|
||||
end
|
||||
if conditions_met then
|
||||
busy_list[i] = true
|
||||
data.timer = data.timer - dt
|
||||
--when time is over, if it wasnt held (or loop is active) then reset and call the function.
|
||||
--held indicates wether the function was called (as active) before last step.
|
||||
if data.timer <= 0 and ((not data.held) or def.loop) then
|
||||
data.held = true
|
||||
table.insert(call_queue, {control=def, active=true, interrupt=false, data=data})
|
||||
elseif def.call_before_timer and not data.held then --this is useful for functions that need to play animations for their progress.
|
||||
table.insert(call_queue, {control=def, active=false, interrupt=false, data=data})
|
||||
if not (self.gun.rechamber_time > 0 and self.gun.ammo_handler.ammo.next_bullet == "empty") then --check if the gun is being charged.
|
||||
for i, control in pairs(self.controls) do
|
||||
if not (i=="on_use") and not (i=="on_secondary_use") then
|
||||
local def = control
|
||||
local data = control.data
|
||||
local conditions_met = true
|
||||
--check no conditions are false
|
||||
for _, key in pairs(control.conditions) do
|
||||
if not pressed[key] then conditions_met = false break end
|
||||
end
|
||||
else
|
||||
data.held = false
|
||||
--detect interrupts, check if the timer was in progress
|
||||
if data.timer ~= def.timer then
|
||||
table.insert(call_queue, {control=def, active=false, interrupt=true, data=data})
|
||||
data.timer = def.timer
|
||||
if conditions_met then
|
||||
busy_list[i] = true
|
||||
data.timer = data.timer - dt
|
||||
--when time is over, if it wasnt held (or loop is active) then reset and call the function.
|
||||
--held indicates wether the function was called (as active) before last step.
|
||||
if data.timer <= 0 and ((not data.held) or def.loop) then
|
||||
data.held = true
|
||||
table.insert(call_queue, {control=def, active=true, interrupt=false, data=data})
|
||||
elseif def.call_before_timer and not data.held then --this is useful for functions that need to play animations for their progress.
|
||||
table.insert(call_queue, {control=def, active=false, interrupt=false, data=data})
|
||||
end
|
||||
else
|
||||
data.held = false
|
||||
--detect interrupts, check if the timer was in progress
|
||||
if data.timer ~= def.timer then
|
||||
table.insert(call_queue, {control=def, active=false, interrupt=true, data=data})
|
||||
data.timer = def.timer
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for i, tbl in pairs(call_queue) do
|
||||
tbl.control.func(tbl.active, tbl.interrupt, tbl.data, busy_list, self.handler.gun, self.handler)
|
||||
end
|
||||
self.busy_list = {}
|
||||
elseif self.busy_list then
|
||||
self.busy_list = nil
|
||||
end
|
||||
for i, tbl in pairs(call_queue) do
|
||||
tbl.control.func(tbl.active, tbl.interrupt, tbl.data, busy_list, self.handler.gun, self.handler)
|
||||
end
|
||||
self.busy_list = {}
|
||||
end
|
||||
function controls:on_use(itemstack, pointed_thing)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
@ -87,7 +91,7 @@ function controls.construct(def)
|
||||
if def.instance then
|
||||
assert(def.controls, "no controls provided")
|
||||
assert(def.player, "no player provided")
|
||||
def.controls = table.deep_copy(def.controls)
|
||||
def.controls = Guns4d.table.deep_copy(def.controls)
|
||||
def.busy_list = {}
|
||||
def.handler = Guns4d.players[def.player:get_player_name()]
|
||||
for i, control in pairs(def.controls) do
|
||||
|
@ -30,7 +30,7 @@ end
|
||||
local function render_length(rotation, fov)
|
||||
local dir = vector.rotate({x=0,y=0,z=1}, {x=rotation.x*math.pi/180,y=0,z=0})
|
||||
vector.rotate(dir,{x=0,y=rotation.y*math.pi/180,z=0})
|
||||
local out = rltv_point_to_hud(dir, fov, 1)
|
||||
local out = Guns4d.rltv_point_to_hud(dir, fov, 1)
|
||||
return math.sqrt(out.x^2+out.y^2)
|
||||
end
|
||||
function Dynamic_crosshair:update(dt)
|
||||
@ -85,13 +85,13 @@ function Dynamic_crosshair:update(dt)
|
||||
|
||||
|
||||
--now figure out what frame will be our correct spread
|
||||
local offset = rltv_point_to_hud(dir, fov, 1) --pretend it's a 1:1 ratio so we can do things correctly.
|
||||
local offset = Guns4d.rltv_point_to_hud(dir, fov, 1) --pretend it's a 1:1 ratio so we can do things correctly.
|
||||
local length = math.sqrt(offset.x^2+offset.y^2) --get the max length.
|
||||
|
||||
local img_perc = (self.scale*2*handler.wininfo.real_hud_scaling*self.width)/handler.wininfo.size.x --the percentage that the hud element takes up
|
||||
local frame = length/img_perc --the percentage of the size the length takes up.
|
||||
frame = math.floor(self.frames*frame)
|
||||
frame = math.clamp(frame, 0, self.frames-1)
|
||||
frame = Guns4d.math.clamp(frame, 0, self.frames-1)
|
||||
--"^[vertical_frame:"..self.frames..":"..frame
|
||||
self.player:hud_change(self.hud, "text", self.image.."^[verticalframe:"..self.frames..":"..frame)
|
||||
else
|
||||
|
113
classes/Gun.lua
113
classes/Gun.lua
@ -84,17 +84,22 @@ local gun_default = {
|
||||
},
|
||||
breathing_scale = .5, --the max angluler offset caused by breathing.
|
||||
controls = { --used by control_handler
|
||||
__overfill=true, --if present, this table will not be filled in.
|
||||
__overfill=true, --this table will not be filled in.
|
||||
aim = Guns4d.default_controls.aim,
|
||||
auto = Guns4d.default_controls.auto,
|
||||
reload = Guns4d.default_controls.reload,
|
||||
on_use = Guns4d.default_controls.on_use,
|
||||
firemode = Guns4d.default_controls.firemode
|
||||
},
|
||||
charging = { --how the gun "cocks"
|
||||
require_charge_on_swap = true,
|
||||
bolt_charge_mode = "none", --"none"-chamber is always full, "catch"-when fired to dry bolt will not need to be charged after reload, "no_catch" bolt will always need to be charged after reload.
|
||||
default_charge_time = 1,
|
||||
},
|
||||
reload = { --used by defualt controls. Still provides usefulness elsewhere.
|
||||
__overfill=true, --if present, this table will not be filled in.
|
||||
{type="unload", time=1, anim="unload", interupt="to_ground", hold = true},
|
||||
{type="load", time=1, anim="load"}
|
||||
__overfill=true,
|
||||
--{type="unload_mag", time=1, anim="unload_mag", interupt="to_ground", hold = true, sound = {sound = "load magazine", pitch = {min=.9, max=1.1}}},
|
||||
--{type="load", time=1, anim="load"}
|
||||
},
|
||||
ammo = { --used by ammo_handler
|
||||
magazine_only = false,
|
||||
@ -105,6 +110,7 @@ local gun_default = {
|
||||
--mesh
|
||||
backface_culling = true,
|
||||
root = "gun",
|
||||
magazine = "magazine",
|
||||
arm_right = "right_aimpoint",
|
||||
arm_left = "left_aimpoint",
|
||||
animations = { --used by animations handler for idle, and default controls
|
||||
@ -112,6 +118,35 @@ local gun_default = {
|
||||
loaded = {x=1,y=1},
|
||||
},
|
||||
},
|
||||
sounds = { --this does not contain reload sound effects.
|
||||
fire = {
|
||||
{
|
||||
sound = "ar_firing",
|
||||
max_hear_distance = 40, --far min_hear_distance is also this.
|
||||
pitch = {
|
||||
min = .95,
|
||||
max = 1.05
|
||||
},
|
||||
gain = {
|
||||
min = .9,
|
||||
max = 1
|
||||
}
|
||||
},
|
||||
{
|
||||
sound = "ar_firing_far",
|
||||
min_hear_distance = 40,
|
||||
max_hear_distance = 600,
|
||||
pitch = {
|
||||
min = .95,
|
||||
max = 1.05
|
||||
},
|
||||
gain = {
|
||||
min = .9,
|
||||
max = 1
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
--inventory_image
|
||||
--inventory_image_empty
|
||||
--used by ammo_handler
|
||||
@ -168,6 +203,7 @@ local gun_default = {
|
||||
KEYFRAME_SAMPLE_PRECISION = .1, --[[what frequency to take precalcualted keyframe samples. The lower this is the higher the memory allocation it will need- though minimal.
|
||||
This will fuck shit up if you change it after gun construction/inheritence (interpolation between precalculated vectors will not work right)]]
|
||||
WAG_CYCLE_SPEED = 1.6,
|
||||
DEFAULT_MAX_HEAR_DISTANCE = 10,
|
||||
DEFAULT_FPS = 60,
|
||||
WAG_DECAY = 1, --divisions per second
|
||||
HAS_RECOIL = true,
|
||||
@ -189,6 +225,7 @@ local gun_default = {
|
||||
}
|
||||
]]
|
||||
},
|
||||
bolt_charged = false,
|
||||
particle_spawners = {},
|
||||
current_firemode = 1,
|
||||
walking_tick = 0,
|
||||
@ -202,7 +239,16 @@ local gun_default = {
|
||||
function gun_default.multiplier_coefficient(multiplier, ratio)
|
||||
return 1+((multiplier*ratio)-ratio)
|
||||
end
|
||||
--update the gun, da meat and da potatoes
|
||||
function gun_default:charge()
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
local props = self.properties
|
||||
if props.visuals.animations.charge then
|
||||
self:set_animation(props.visuals.animations.charge, props.charging.default_charge_time)
|
||||
end
|
||||
self.ammo_handler:close_bolt()
|
||||
self.rechamber_time = props.charging.default_charge_time
|
||||
end
|
||||
--update gun, the main function.
|
||||
function gun_default:update(dt)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
if not self:has_entity() then self:add_entity(); self:clear_animation() end
|
||||
@ -251,6 +297,13 @@ function gun_default:update(dt)
|
||||
self.crosshair:update()
|
||||
end
|
||||
|
||||
--automatically cock if uncocked.
|
||||
local ammo = self.ammo_handler.ammo
|
||||
--[[if ammo.total_bullets and (ammo.total_bullets > 0 and ammo.next_bullet == "empty") then
|
||||
self:charge()
|
||||
end]]
|
||||
print(dump(self.ammo_handler.ammo.next_bullet))
|
||||
|
||||
local offsets = self.offsets
|
||||
--local player_axial = offsets.recoil.player_axial + offsets.walking.player_axial + offsets.sway.player_axial + offsets.breathing.player_axial
|
||||
--local gun_axial = offsets.recoil.gun_axial + offsets.walking.gun_axial + offsets.sway.gun_axial
|
||||
@ -298,9 +351,9 @@ function gun_default:update_image_and_text_meta(meta)
|
||||
end
|
||||
--pick the image
|
||||
local image = self.properties.inventory_image
|
||||
if ammo.total_bullets > 0 then
|
||||
if (ammo.total_bullets > 0) and not ammo.magazine_psuedo_empty then
|
||||
image = self.properties.inventory_image
|
||||
elseif self.properties.inventory_image_magless and (ammo.loaded_mag == "empty" or ammo.loaded_mag == "") then
|
||||
elseif self.properties.inventory_image_magless and ( (ammo.loaded_mag == "empty") or (ammo.loaded_mag == "") or ammo.magazine_psuedo_empty) then
|
||||
image = self.properties.inventory_image_magless
|
||||
elseif self.properties.inventory_image_empty then
|
||||
image = self.properties.inventory_image_empty
|
||||
@ -321,9 +374,10 @@ function gun_default:attempt_fire()
|
||||
if spent_bullet and spent_bullet ~= "empty" then
|
||||
local dir = self.dir
|
||||
local pos = self.pos
|
||||
local bullet_def = table.fill(Guns4d.ammo.registered_bullets[spent_bullet], {
|
||||
local bullet_def = Guns4d.table.fill(Guns4d.ammo.registered_bullets[spent_bullet], {
|
||||
player = self.player,
|
||||
pos = pos,
|
||||
--we don't want it to be doing fuckshit and letting players shoot through walls.
|
||||
pos = pos-((self.handler.control_handler.ads and dir*self.properties.ads.offset.z) or dir*self.properties.hip.offset.z),
|
||||
dir = dir,
|
||||
gun = self
|
||||
})
|
||||
@ -333,19 +387,29 @@ function gun_default:attempt_fire()
|
||||
end
|
||||
self:recoil()
|
||||
self:muzzle_flash()
|
||||
|
||||
local fire_sound = Guns4d.table.deep_copy(self.properties.sounds.fire) --important that we copy because play_sounds modifies it.
|
||||
fire_sound.pos = self.pos
|
||||
Guns4d.play_sounds(fire_sound)
|
||||
|
||||
self.rechamber_time = 60/self.properties.firerateRPM
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function rand_sign(b)
|
||||
b = b or .5
|
||||
local int = 1
|
||||
if math.random() > b then int=-1 end
|
||||
return int
|
||||
end
|
||||
function gun_default:recoil()
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
local rprops = self.properties.recoil
|
||||
for axis, recoil in pairs(self.velocities.recoil) do
|
||||
for _, i in pairs({"x","y"}) do
|
||||
recoil[i] = recoil[i] + (rprops.angular_velocity[axis][i]
|
||||
*math.rand_sign((rprops.bias[axis][i]/2)+.5))
|
||||
*rand_sign((rprops.bias[axis][i]/2)+.5))
|
||||
*self.multiplier_coefficient(rprops.hipfire_multiplier[axis], 1-self.handler.ads_location)
|
||||
end
|
||||
end
|
||||
@ -539,7 +603,7 @@ function gun_default:update_recoil(dt)
|
||||
for axis, _ in pairs(self.offsets.recoil) do
|
||||
for _, i in pairs({"x","y"}) do
|
||||
local recoil = self.offsets.recoil[axis][i]
|
||||
local recoil_vel = math.clamp(self.velocities.recoil[axis][i],-self.properties.recoil.angular_velocity_max[axis],self.properties.recoil.angular_velocity_max[axis])
|
||||
local recoil_vel = Guns4d.math.clamp(self.velocities.recoil[axis][i],-self.properties.recoil.angular_velocity_max[axis],self.properties.recoil.angular_velocity_max[axis])
|
||||
local old_recoil_vel = recoil_vel
|
||||
recoil = recoil + recoil_vel
|
||||
if math.abs(recoil_vel) > 0.01 then
|
||||
@ -560,7 +624,7 @@ function gun_default:update_recoil(dt)
|
||||
if math.abs(recoil) > 0.001 then
|
||||
local correction_multiplier = self.time_since_last_fire*self.properties.recoil.target_correction_factor[axis]
|
||||
local correction_value = recoil*correction_multiplier
|
||||
correction_value = math.clamp(math.abs(correction_value), 0, self.properties.recoil.target_correction_max_rate[axis])
|
||||
correction_value = Guns4d.math.clamp(math.abs(correction_value), 0, self.properties.recoil.target_correction_max_rate[axis])
|
||||
recoil=recoil-(correction_value*dt*(math.abs(recoil)/recoil))
|
||||
--prevent overcorrection
|
||||
if math.abs(recoil) > math.abs(old_recoil) then
|
||||
@ -576,7 +640,7 @@ function gun_default:update_animation(dt)
|
||||
local ent = self.entity
|
||||
local data = self.animation_data
|
||||
data.runtime = data.runtime + dt
|
||||
data.current_frame = math.clamp(data.current_frame+(dt*data.fps), data.frames.x, data.frames.y)
|
||||
data.current_frame = Guns4d.math.clamp(data.current_frame+(dt*data.fps), data.frames.x, data.frames.y)
|
||||
if data.loop and (data.current_frame > data.frames.y) then
|
||||
data.current_frame = data.frames.x
|
||||
end
|
||||
@ -743,7 +807,7 @@ gun_default.construct = function(def)
|
||||
def.meta = meta
|
||||
--create ID so we can track switches between weapons, also get some other data.
|
||||
if meta:get_string("guns4d_id") == "" then
|
||||
local id = tostring(Unique_id.generate())
|
||||
local id = tostring(Guns4d.unique_id.generate())
|
||||
meta:set_string("guns4d_id", id)
|
||||
def.player:set_wielded_item(def.itemstack)
|
||||
def.id = id
|
||||
@ -756,10 +820,15 @@ gun_default.construct = function(def)
|
||||
def.ammo_handler = def.properties.ammo_handler:new({ --initialize ammo handler from gun and gun metadata.
|
||||
gun = def
|
||||
})
|
||||
local ammo = def.ammo_handler.ammo
|
||||
if def.properties.require_charge_on_swap then
|
||||
ammo.next_bullet = "empty"
|
||||
end
|
||||
minetest.after(0, function() if ammo.total_bullets > 0 then def:charge() end end)
|
||||
def:update_image_and_text_meta() --has to be called manually in post as ammo_handler would not exist yet.
|
||||
def.player:set_wielded_item(def.itemstack)
|
||||
--unavoidable table instancing
|
||||
def.properties = table.fill(def.base_class.properties, def.properties)
|
||||
def.properties = Guns4d.table.fill(def.base_class.properties, def.properties)
|
||||
def.particle_spawners = {} --Instantiatable_class only shallow copies. So tables will not change, and thus some need to be initialized.
|
||||
def.property_modifiers = {}
|
||||
def.total_offset_rotation = {
|
||||
@ -768,7 +837,7 @@ gun_default.construct = function(def)
|
||||
}
|
||||
def.player_rotation = Vec.new()
|
||||
--initialize all offsets
|
||||
--def.offsets = table.deep_copy(def.base_class.offsets)
|
||||
--def.offsets = Guns4d.table.deep_copy(def.base_class.offsets)
|
||||
def.offsets = {}
|
||||
for offset, tbl in pairs(def.base_class.offsets) do
|
||||
def.offsets[offset] = {}
|
||||
@ -781,7 +850,7 @@ gun_default.construct = function(def)
|
||||
end
|
||||
end
|
||||
def.animation_rotation = vector.new()
|
||||
--def.velocities = table.deep_copy(def.base_class.velocities)
|
||||
--def.velocities = Guns4d.table.deep_copy(def.base_class.velocities)
|
||||
def.velocities = {}
|
||||
for i, tbl in pairs(def.base_class.velocities) do
|
||||
def.velocities[i] = {}
|
||||
@ -817,8 +886,8 @@ gun_default.construct = function(def)
|
||||
end
|
||||
|
||||
--fill in the properties.
|
||||
def.properties = table.fill(def.parent_class.properties, props or {})
|
||||
def.consts = table.fill(def.parent_class.consts, def.consts or {})
|
||||
def.properties = Guns4d.table.fill(def.parent_class.properties, props or {})
|
||||
def.consts = Guns4d.table.fill(def.parent_class.consts, def.consts or {})
|
||||
props = def.properties --have to reinitialize this as the reference is replaced.
|
||||
|
||||
--print(table.tostring(props))
|
||||
@ -856,13 +925,13 @@ gun_default.construct = function(def)
|
||||
table.insert(def.b3d_model.global_frames.rotation, newvec)
|
||||
end
|
||||
end
|
||||
if main then
|
||||
--[[if main then
|
||||
local quat = mtul.math.quat.new(main.keys[1].rotation)
|
||||
print(dump(main.keys[1]), vector.new(quat:to_euler_angles_unpack(quat)))
|
||||
end
|
||||
for i, v in pairs(def.b3d_model.global_frames.rotation) do
|
||||
print(i, dump(vector.new(v:to_euler_angles_unpack())*180/math.pi))
|
||||
end
|
||||
end]]
|
||||
--print()
|
||||
-- if it's not a template, then create an item, override some props
|
||||
if def.name ~= "__template" then
|
||||
|
@ -39,7 +39,7 @@ function player_handler:update(dt)
|
||||
self.player_model_handler = nil
|
||||
end
|
||||
self.player_model_handler = Guns4d.player_model_handler.get_handler(self:get_properties().mesh):new({player=self.player})
|
||||
self.control_handler = Guns4d.control_handler:new({player=player, controls=self.gun.properties.controls})
|
||||
self.control_handler = Guns4d.control_handler:new({player=player, controls=self.gun.properties.controls, gun=self.gun})
|
||||
|
||||
--this needs to be stored for when the gun is unset!
|
||||
self.horizontal_offset = self.gun.properties.ads.horizontal_offset
|
||||
@ -50,7 +50,7 @@ function player_handler:update(dt)
|
||||
--for the gun's scopes to work properly we need predictable offsets.
|
||||
end
|
||||
--update some properties.
|
||||
self.look_rotation.x, self.look_rotation.y = math.clamp((player:get_look_vertical() or 0)*180/math.pi, -80, 80), -player:get_look_horizontal()*180/math.pi
|
||||
self.look_rotation.x, self.look_rotation.y = Guns4d.math.clamp((player:get_look_vertical() or 0)*180/math.pi, -80, 80), -player:get_look_horizontal()*180/math.pi
|
||||
if TICK % 10 == 0 then
|
||||
self.wininfo = minetest.get_player_window_information(self.player:get_player_name())
|
||||
end
|
||||
@ -80,13 +80,13 @@ function player_handler:update(dt)
|
||||
--eye offsets and ads_location
|
||||
if (self.control_handler and self.control_handler.ads) and (self.ads_location<1) then
|
||||
--if aiming, then increase ADS location
|
||||
self.ads_location = math.clamp(self.ads_location + (dt/self.gun.properties.ads.aim_time), 0, 1)
|
||||
self.ads_location = Guns4d.math.clamp(self.ads_location + (dt/self.gun.properties.ads.aim_time), 0, 1)
|
||||
elseif ((not self.control_handler) or (not self.control_handler.ads)) and self.ads_location>0 then
|
||||
local divisor = .2
|
||||
if self.gun then
|
||||
divisor = self.gun.properties.ads.aim_time/self.gun.consts.AIM_OUT_AIM_IN_SPEED_RATIO
|
||||
end
|
||||
self.ads_location = math.clamp(self.ads_location - (dt/divisor), 0, 1)
|
||||
self.ads_location = Guns4d.math.clamp(self.ads_location - (dt/divisor), 0, 1)
|
||||
end
|
||||
|
||||
self.look_offset.x = self.horizontal_offset*self.ads_location
|
||||
@ -162,7 +162,7 @@ end
|
||||
function player_handler:set_properties(properties)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
self.player:set_properties(properties)
|
||||
self.properties = table.fill(self.properties, properties)
|
||||
self.properties = Guns4d.table.fill(self.properties, properties)
|
||||
end
|
||||
function player_handler:is_holding_gun()
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
@ -208,7 +208,7 @@ function player_handler.construct(def)
|
||||
def[i] = v
|
||||
end
|
||||
end
|
||||
def.look_rotation = table.deep_copy(player_handler.look_rotation)
|
||||
def.look_rotation = Guns4d.table.deep_copy(player_handler.look_rotation)
|
||||
def.infinite_ammo = minetest.check_player_privs(def.player, Guns4d.config.infinite_ammo_priv)
|
||||
end
|
||||
end
|
||||
|
@ -31,9 +31,9 @@ local Sprite_scope = Instantiatable_class:inherit({
|
||||
def.player = def.gun.player
|
||||
def.handler = def.gun.handler
|
||||
def.elements = {}
|
||||
local new_images = table.deep_copy(def.images)
|
||||
local new_images = Guns4d.table.deep_copy(def.images)
|
||||
if def.images then
|
||||
def.images = table.fill(new_images, def.images)
|
||||
def.images = Guns4d.table.fill(new_images, def.images)
|
||||
end
|
||||
for i, v in pairs(def.images) do
|
||||
def.elements[i] = def.player:hud_add{
|
||||
@ -63,12 +63,12 @@ function Sprite_scope:update()
|
||||
dir = dir + (self.gun.properties.ads.offset+vector.new(self.gun.properties.ads.horizontal_offset,0,0))*0
|
||||
end
|
||||
local fov = self.player:get_fov()
|
||||
local real_aim = rltv_point_to_hud(dir, fov, ratio)
|
||||
local anim_aim = rltv_point_to_hud(vector.rotate({x=0,y=0,z=1}, self.gun.animation_rotation*math.pi/180), fov, ratio)
|
||||
local real_aim = Guns4d.rltv_point_to_hud(dir, fov, ratio)
|
||||
local anim_aim = Guns4d.rltv_point_to_hud(vector.rotate({x=0,y=0,z=1}, self.gun.animation_rotation*math.pi/180), fov, ratio)
|
||||
real_aim.x = real_aim.x+anim_aim.x; real_aim.y = real_aim.y+anim_aim.y
|
||||
|
||||
--print(dump(self.gun.animation_rotation))
|
||||
local paxial_aim = rltv_point_to_hud(self.gun.local_paxial_dir, fov, ratio)
|
||||
local paxial_aim = Guns4d.rltv_point_to_hud(self.gun.local_paxial_dir, fov, ratio)
|
||||
--so custom scopes can do their thing without doing more calcs
|
||||
self.hud_projection_real = real_aim
|
||||
self.hud_projection_paxial = paxial_aim
|
||||
|
@ -46,6 +46,7 @@ Guns4d.default_controls.reload = {
|
||||
conditions = {"zoom"},
|
||||
loop = false,
|
||||
timer = 0, --1 so we have a call to initialize the timer.
|
||||
--remember that the data table allows us to store arbitrary data
|
||||
func = function(active, interrupted, data, busy_list, gun, handler)
|
||||
local ammo_handler = gun.ammo_handler
|
||||
local props = gun.properties
|
||||
@ -55,28 +56,37 @@ Guns4d.default_controls.reload = {
|
||||
end
|
||||
local this_state = props.reload[data.state]
|
||||
local next_state_index = data.state
|
||||
local next_state = props.reload[next_state_index+1]
|
||||
|
||||
--this elseif chain has gotten egregiously long, so I'll have to create a system for registering these reload states eventually- both for the sake of organization aswell as a modular API.
|
||||
if next_state_index == 0 then
|
||||
|
||||
--nothing to do, let animations get set down the line.
|
||||
next_state_index = next_state_index + 1
|
||||
|
||||
elseif type(this_state.type) == "function" then
|
||||
|
||||
this_state.type(true, handler, gun)
|
||||
|
||||
elseif this_state.type == "unload" then
|
||||
local pause = false
|
||||
local next = props.reload[next_state_index+1]
|
||||
if (next.type=="load_fractional" or next.type=="load") and (not ammo_handler:inventory_has_ammo()) then
|
||||
pause=true
|
||||
elseif this_state.type == "unload_mag" then
|
||||
|
||||
next_state_index = next_state_index + 1
|
||||
if next_state and next_state.type == "store" then
|
||||
ammo_handler:set_unloading(true) --if interrupted it will drop to ground, so just make it appear as if the gun is already unloaded.
|
||||
else
|
||||
ammo_handler:unload_magazine(true) --unload to ground
|
||||
end
|
||||
|
||||
elseif this_state.type == "store" then
|
||||
|
||||
local pause = false
|
||||
--needs to happen before so we don't detect the ammo we just unloaded
|
||||
if next_state and (next_state.type=="load_fractional" or next_state.type=="load") and (not ammo_handler:inventory_has_ammo()) then
|
||||
pause=true
|
||||
end
|
||||
if props.ammo.magazine_only and (ammo_handler.ammo.loaded_mag ~= "empty") then
|
||||
ammo_handler:unload_magazine()
|
||||
else
|
||||
ammo_handler:unload_all()
|
||||
end
|
||||
|
||||
--if there's no ammo make hold so you don't reload the same ammo you just unloaded.
|
||||
if pause then
|
||||
return
|
||||
@ -91,17 +101,26 @@ Guns4d.default_controls.reload = {
|
||||
else
|
||||
ammo_handler:load_flat()
|
||||
end
|
||||
next_state_index = next_state_index +1
|
||||
|
||||
if not (next_state or (next_state.type ~= "charge")) then
|
||||
--chamber the round automatically.
|
||||
ammo_handler:close_bolt()
|
||||
end
|
||||
next_state_index = next_state_index + 1
|
||||
|
||||
elseif this_state.type == "charge" then
|
||||
|
||||
next_state_index = next_state_index + 1
|
||||
ammo_handler:close_bolt()
|
||||
--if not
|
||||
|
||||
elseif this_state.type == "unload_fractional" then
|
||||
|
||||
ammo_handler:unload_fractional()
|
||||
if ammo_handler.ammo.total_bullets == 0 then
|
||||
next_state_index = next_state_index + 1
|
||||
end
|
||||
|
||||
elseif this_state.type == "load_fractional" then
|
||||
|
||||
ammo_handler:load_fractional()
|
||||
if ammo_handler.ammo.total_bullets == props.ammo.capacity then
|
||||
next_state_index = next_state_index + 1
|
||||
@ -117,76 +136,107 @@ Guns4d.default_controls.reload = {
|
||||
--check that the next states are actually valid, if not, skip them
|
||||
local valid_state = false
|
||||
while not valid_state do
|
||||
local state_changed = false
|
||||
next_state = props.reload[next_state_index]
|
||||
if next_state then
|
||||
local state_changed = false
|
||||
|
||||
if next_state.type == "unload" then
|
||||
--determine wether the next_state is valid (can actually be completed)
|
||||
local invalid_state = false
|
||||
if next_state.type == "store" then
|
||||
|
||||
if props.ammo.magazine_only and (ammo_handler.ammo.loaded_mag == "empty") then
|
||||
state_changed = true
|
||||
invalid_state = true
|
||||
end
|
||||
--need to check for inventory room, because otherwise we just want to drop it to the ground.
|
||||
--[[
|
||||
if ... then
|
||||
if props.ammo.magazine_only and (ammo_handler.ammo.loaded_mag ~= "empty") then
|
||||
ammo_handler:unload_magazine(true)
|
||||
else
|
||||
ammo_handler:unload_all(true)
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
elseif next_state.type == "unload_fractional" then
|
||||
--[[elseif next_state.type == "unload_fractional" then --UNIMPLEMENTED
|
||||
|
||||
if not ammo_handler.ammo.total_bullets > 0 then
|
||||
state_changed = true
|
||||
invalid_state = true
|
||||
end]]
|
||||
elseif next_state.type == "unload_mag" then
|
||||
|
||||
if ammo_handler.ammo.loaded_mag == "empty" then
|
||||
invalid_state = true
|
||||
end
|
||||
|
||||
elseif next_state.type == "load" then
|
||||
--check we have ammo
|
||||
if props.ammo.magazine_only then
|
||||
if not ammo_handler:can_load_magazine() then
|
||||
state_changed = true
|
||||
invalid_state = true
|
||||
end
|
||||
else
|
||||
|
||||
if not ammo_handler:can_load_flat() then
|
||||
state_changed = true
|
||||
invalid_state = true
|
||||
end
|
||||
end
|
||||
end
|
||||
if not state_changed then
|
||||
if not invalid_state then
|
||||
valid_state=true
|
||||
else
|
||||
next_state_index = next_state_index + 1
|
||||
next_state = props.reload[next_state_index]
|
||||
end
|
||||
else
|
||||
--if the next state doesn't exist, we've reached the end (the gun is reloaded) and we should restart. "held" so it doesn't continue unless the user lets go of the input button.
|
||||
data.state = 0
|
||||
data.timer = 0.5
|
||||
data.held = true
|
||||
return
|
||||
end
|
||||
end
|
||||
--check if we're at cycle end
|
||||
if next_state == nil then
|
||||
--I don't think this is needed given the above.
|
||||
--[[ if next_state == nil then
|
||||
data.state = 0
|
||||
data.timer = 0
|
||||
data.held = true
|
||||
return
|
||||
else
|
||||
data.state = next_state_index
|
||||
data.timer = next_state.time
|
||||
data.held = false
|
||||
local anim = next_state.anim
|
||||
if type(next_state.anim) == "string" then
|
||||
anim = props.visuals.animations[next_state.anim]
|
||||
end
|
||||
if anim then
|
||||
else]]
|
||||
data.state = next_state_index
|
||||
data.timer = next_state.time
|
||||
data.held = false
|
||||
local anim = next_state.anim
|
||||
if type(next_state.anim) == "string" then
|
||||
anim = props.visuals.animations[next_state.anim]
|
||||
end
|
||||
if anim then
|
||||
if anim.x and anim.y then
|
||||
gun:set_animation(anim, next_state.time)
|
||||
else
|
||||
minetest.log("error", "improperly set gun reload animation, reload state `"..next_state.type.."`, gun `"..gun.itemstring.."`")
|
||||
end
|
||||
end
|
||||
if next_state.sounds then
|
||||
local sounds = Guns4d.table.deep_copy(props.reload[next_state_index].sounds)
|
||||
sounds.pos = gun.pos
|
||||
sounds.max_hear_distance = sounds.max_hear_distance or gun.consts.DEFAULT_MAX_HEAR_DISTANCE
|
||||
data.played_sounds = Guns4d.play_sounds(sounds)
|
||||
end
|
||||
print(dump(next_state_index))
|
||||
--end
|
||||
elseif interrupted then
|
||||
local this_state = props.reload[data.state]
|
||||
if this_state and (this_state.type == "unload") and (this_state.interupt == "to_ground") then
|
||||
--true indicates to_ground (meaning they will be removed)
|
||||
if this_state and (this_state.type == "store") then
|
||||
--if the player was about to store the mag, eject it.
|
||||
if props.ammo.magazine_only and (ammo_handler.ammo.loaded_mag ~= "empty") then
|
||||
ammo_handler:unload_magazine(true)
|
||||
ammo_handler:unload_magazine(true) --"true" is for to_ground
|
||||
else
|
||||
ammo_handler:unload_all(true)
|
||||
end
|
||||
end
|
||||
if data.played_sounds then
|
||||
Guns4d.stop_sounds(data.played_sounds)
|
||||
data.played_sounds = nil
|
||||
end
|
||||
gun:clear_animation()
|
||||
data.state = 0
|
||||
end
|
||||
|
11
ldoc/config.ld
Normal file
11
ldoc/config.ld
Normal file
@ -0,0 +1,11 @@
|
||||
project="4dguns"
|
||||
title="4dguns documentation"
|
||||
description="THEE ultimate 3d gun library."
|
||||
format="markdown"
|
||||
backtick_references=false
|
||||
file = {
|
||||
"../",
|
||||
}
|
||||
dir='../autogen_docs'
|
||||
readme='../README.md'
|
||||
style='!new'
|
13
ldoc/install_and_build_docs
Normal file
13
ldoc/install_and_build_docs
Normal file
@ -0,0 +1,13 @@
|
||||
#! /bin/sh
|
||||
|
||||
# on github, leafo/gh-actions-lua leafo/gh-actions-luarocks setup luarocks for us.
|
||||
#~ sudo apt-get install lua5.3 liblua5.3-dev luarocks
|
||||
|
||||
# github ldoc is far ahead of the released version.
|
||||
echo ldoc version:
|
||||
git ls-remote https://github.com/lunarmodules/LDoc master
|
||||
luarocks --local install https://raw.githubusercontent.com/lunarmodules/LDoc/master/ldoc-scm-3.rockspec
|
||||
|
||||
echo
|
||||
cd ./doc
|
||||
~/.luarocks/bin/ldoc .
|
3
ldoc/windows_quick_generate.bat
Normal file
3
ldoc/windows_quick_generate.bat
Normal file
@ -0,0 +1,3 @@
|
||||
# literally just so I dont have to open powershell every time.
|
||||
@echo off
|
||||
ldoc .
|
122
misc_helpers.lua
122
misc_helpers.lua
@ -1,14 +1,15 @@
|
||||
--can't be copyright claimed by myself, luckily... well actually knowing the legal system I probably could sue myself.
|
||||
Unique_id = {
|
||||
--- misc. common tools for 4dguns
|
||||
-- @script misc_helpers
|
||||
|
||||
Guns4d.math = {}
|
||||
Guns4d.table = {}
|
||||
|
||||
--store this so there arent duplicates
|
||||
Guns4d.unique_id = {
|
||||
generated = {},
|
||||
}
|
||||
function math.clamp(val, lower, upper)
|
||||
if lower > upper then lower, upper = upper, lower end
|
||||
return math.max(lower, math.min(upper, val))
|
||||
end
|
||||
--I need to store this so there arent duplicates lol
|
||||
function Unique_id.generate()
|
||||
local genned_ids = Unique_id.generated
|
||||
function Guns4d.unique_id.generate()
|
||||
local genned_ids = Guns4d.unique_id.generated
|
||||
local id = string.sub(tostring(math.random()), 3)
|
||||
while genned_ids[id] do
|
||||
id = string.sub(tostring(math.random()), 3)
|
||||
@ -16,8 +17,24 @@ function Unique_id.generate()
|
||||
genned_ids[id] = true
|
||||
return id
|
||||
end
|
||||
--i probably should stop violating the math namespace, but I'll worry about that *later*
|
||||
function math.weighted_randoms(tbl)
|
||||
|
||||
---math helpers.
|
||||
-- in guns4d.math
|
||||
--@section math
|
||||
|
||||
--all of the following is disgusting and violates the namespace because I got used to love2d.
|
||||
function Guns4d.math.clamp(val, lower, upper)
|
||||
if lower > upper then lower, upper = upper, lower end
|
||||
return math.max(lower, math.min(upper, val))
|
||||
end
|
||||
--- picks a random index, with odds based on it's value. Returns the index of the selected.
|
||||
-- @param tbl a table containing weights, example
|
||||
-- {
|
||||
-- ["sound"] = 999, --999 in 1000 chance this is chosen
|
||||
-- ["rare_sound"] = 1 --1 in 1000 chance this is chosen
|
||||
-- }
|
||||
-- @function weighted_randoms
|
||||
function Guns4d.math.weighted_randoms(tbl)
|
||||
local total_weight = 0
|
||||
local new_tbl = {}
|
||||
for i, v in pairs(tbl) do
|
||||
@ -39,38 +56,13 @@ function math.weighted_randoms(tbl)
|
||||
scaled_weight = scaled_weight + v[2]
|
||||
end
|
||||
end
|
||||
--[[function math.get_rotation(dir)
|
||||
local x = math.atan2(dir.y, dir.z)
|
||||
local y =-math.atan2(dir.x, dir.z)
|
||||
return vector.new(
|
||||
x,
|
||||
y,
|
||||
0
|
||||
)
|
||||
end]]
|
||||
--from luatic's old modlib, doesn't work to fix gimble lock, actually makes things worse (somehow)
|
||||
function math.get_rotation(dir)
|
||||
return vector.new(
|
||||
math.atan2(dir.y, math.sqrt(dir.x^2 + dir.z^2)),
|
||||
-math.atan2(dir.x, dir.z),
|
||||
0
|
||||
)
|
||||
end
|
||||
|
||||
function math.rand_sign(b)
|
||||
b = b or .5
|
||||
local int = 1
|
||||
if math.random() > b then int=-1 end
|
||||
return int
|
||||
end
|
||||
--weighted randoms
|
||||
|
||||
--[[
|
||||
--for table vectors that aren't vector objects
|
||||
---@diagnostic disable-next-line: lowercase-global
|
||||
function tolerance_check(a,b,tolerance)
|
||||
local function tolerance_check(a,b,tolerance)
|
||||
return math.abs(a-b) > tolerance
|
||||
end
|
||||
function vector.equals_tolerance(v, vb, tolerance)
|
||||
function Guns4d.math.vectors_in_tolerance(v, vb, tolerance)
|
||||
tolerance = tolerance or 0
|
||||
return (
|
||||
tolerance_check(v.x, vb.x, tolerance) and
|
||||
@ -78,14 +70,20 @@ function vector.equals_tolerance(v, vb, tolerance)
|
||||
tolerance_check(v.z, vb.z, tolerance)
|
||||
)
|
||||
end
|
||||
]]
|
||||
|
||||
---table helpers.
|
||||
-- in guns4d.table
|
||||
--@section table
|
||||
|
||||
--copy everything
|
||||
function table.deep_copy(tbl, copy_metatable, indexed_tables)
|
||||
function Guns4d.table.deep_copy(tbl, copy_metatable, indexed_tables)
|
||||
if not indexed_tables then indexed_tables = {} end
|
||||
local new_table = {}
|
||||
local metat = getmetatable(tbl)
|
||||
if metat then
|
||||
if copy_metatable then
|
||||
setmetatable(new_table, table.deep_copy(metat, true))
|
||||
setmetatable(new_table, Guns4d.table.deep_copy(metat, true))
|
||||
else
|
||||
setmetatable(new_table, metat)
|
||||
end
|
||||
@ -94,7 +92,7 @@ function table.deep_copy(tbl, copy_metatable, indexed_tables)
|
||||
if type(v) == "table" then
|
||||
if not indexed_tables[v] then
|
||||
indexed_tables[v] = true
|
||||
new_table[i] = table.deep_copy(v, copy_metatable)
|
||||
new_table[i] = Guns4d.table.deep_copy(v, copy_metatable)
|
||||
end
|
||||
else
|
||||
new_table[i] = v
|
||||
@ -104,7 +102,7 @@ function table.deep_copy(tbl, copy_metatable, indexed_tables)
|
||||
end
|
||||
|
||||
|
||||
function table.contains(tbl, value)
|
||||
function Guns4d.table.contains(tbl, value)
|
||||
for i, v in pairs(tbl) do
|
||||
if v == value then
|
||||
return i
|
||||
@ -120,7 +118,8 @@ local function parse_index(i)
|
||||
end
|
||||
end
|
||||
--dump() sucks.
|
||||
function table.tostring(tbl, shallow, list_length_lim, depth_limit, tables, depth)
|
||||
local table_contains = Guns4d.table.contains
|
||||
function Guns4d.table.tostring(tbl, shallow, list_length_lim, depth_limit, tables, depth)
|
||||
--create a list of tables that have been tostringed in this chain
|
||||
if not table then return "nil" end
|
||||
if not tables then tables = {this_table = tbl} end
|
||||
@ -141,11 +140,11 @@ function table.tostring(tbl, shallow, list_length_lim, depth_limit, tables, dept
|
||||
if val_type == "string" then
|
||||
str = str..initial_string..parse_index(i).." = \""..v.."\","
|
||||
elseif val_type == "table" and (not shallow) then
|
||||
local contains = table.contains(tables, v)
|
||||
local contains = table_contains(tables, v)
|
||||
--to avoid infinite loops, make sure that the table has not been tostringed yet
|
||||
if not contains then
|
||||
tables[i] = v
|
||||
str = str..initial_string..parse_index(i).." = "..table.tostring(v, shallow, list_length_lim, depth_limit, tables, depth)..","
|
||||
str = str..initial_string..parse_index(i).." = "..Guns4d.table.tostring(v, shallow, list_length_lim, depth_limit, tables, depth)..","
|
||||
else
|
||||
str = str..initial_string..parse_index(i).." = "..tostring(v).." (index: '"..tostring(contains).."'),"
|
||||
end
|
||||
@ -158,7 +157,7 @@ function table.tostring(tbl, shallow, list_length_lim, depth_limit, tables, dept
|
||||
end
|
||||
return str..string.sub(initial_string, 1, -5).."}"
|
||||
end
|
||||
function table.tostring_structure_only(tbl, shallow, tables, depth)
|
||||
--[[function Guns4d.table.tostring_structure_only(tbl, shallow, tables, depth)
|
||||
--create a list of tables that have been tostringed in this chain
|
||||
if not table then return "nil" end
|
||||
if not tables then tables = {this_table = tbl} end
|
||||
@ -183,11 +182,11 @@ function table.tostring_structure_only(tbl, shallow, tables, depth)
|
||||
iterations = iterations + 1
|
||||
local val_type = type(v)
|
||||
if val_type == "table" then
|
||||
local contains = table.contains(tables, v)
|
||||
local contains = table_contains(tables, v)
|
||||
--to avoid infinite loops, make sure that the table has not been tostringed yet
|
||||
if not contains then
|
||||
tables[parse_index(i).." ["..tostring(v).."]"] = v
|
||||
str = str..initial_string..parse_index(i).."("..tostring(v)..") = "..table.tostring_structure_only(v, shallow, tables, depth)..","
|
||||
str = str..initial_string..parse_index(i).."("..tostring(v)..") = "..Guns4d.table.tostring_structure_only(v, shallow, tables, depth)..","
|
||||
elseif type(v) == "table" then
|
||||
str = str..initial_string..parse_index(i).." = "..tostring(v)
|
||||
else
|
||||
@ -201,14 +200,14 @@ function table.tostring_structure_only(tbl, shallow, tables, depth)
|
||||
return "table too long"
|
||||
end
|
||||
return "{"..str..string.sub(initial_string, 1, -5).."}"
|
||||
end
|
||||
end]]
|
||||
|
||||
--replace fields (and fill sub-tables) in `tbl` with elements in `replacement`. Recursively iterates all sub-tables. use property __overfill=true for subtables that don't want to be overfilled.
|
||||
function table.fill(tbl, replacement, preserve_reference, indexed_tables)
|
||||
function Guns4d.table.fill(tbl, replacement, preserve_reference, indexed_tables)
|
||||
if not indexed_tables then indexed_tables = {} end --store tables to prevent circular referencing
|
||||
local new_table = tbl
|
||||
if not preserve_reference then
|
||||
new_table = table.deep_copy(tbl)
|
||||
new_table = Guns4d.table.deep_copy(tbl)
|
||||
end
|
||||
for i, v in pairs(replacement) do
|
||||
if new_table[i] then
|
||||
@ -218,13 +217,13 @@ function table.fill(tbl, replacement, preserve_reference, indexed_tables)
|
||||
if not indexed_tables[v] then
|
||||
if not new_table[i].__overfill then
|
||||
indexed_tables[v] = true
|
||||
new_table[i] = table.fill(tbl[i], replacement[i], false, indexed_tables)
|
||||
new_table[i] = Guns4d.table.fill(tbl[i], replacement[i], false, indexed_tables)
|
||||
else --if overfill is present, we don't want to preserve the old table.
|
||||
new_table[i] = table.deep_copy(replacement[i])
|
||||
new_table[i] = Guns4d.table.deep_copy(replacement[i])
|
||||
end
|
||||
end
|
||||
elseif not replacement[i].__no_copy then
|
||||
new_table[i] = table.deep_copy(replacement[i])
|
||||
new_table[i] = Guns4d.table.deep_copy(replacement[i])
|
||||
else
|
||||
new_table[i] = replacement[i]
|
||||
end
|
||||
@ -239,7 +238,7 @@ function table.fill(tbl, replacement, preserve_reference, indexed_tables)
|
||||
return new_table
|
||||
end
|
||||
--for class based OOP, ensure values containing a table in btbl are tables in a_tbl- instantiate, but do not fill.
|
||||
function table.instantiate_struct(tbl, btbl, indexed_tables)
|
||||
--[[function table.instantiate_struct(tbl, btbl, indexed_tables)
|
||||
if not indexed_tables then indexed_tables = {} end --store tables to prevent circular referencing
|
||||
for i, v in pairs(btbl) do
|
||||
if type(v) == "table" and not indexed_tables[v] then
|
||||
@ -252,8 +251,8 @@ function table.instantiate_struct(tbl, btbl, indexed_tables)
|
||||
end
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
function table.shallow_copy(t)
|
||||
end]]
|
||||
function Guns4d.table.shallow_copy(t)
|
||||
local new_table = {}
|
||||
for i, v in pairs(t) do
|
||||
new_table[i] = v
|
||||
@ -261,14 +260,15 @@ function table.shallow_copy(t)
|
||||
return new_table
|
||||
end
|
||||
|
||||
---other helpers
|
||||
--@section other
|
||||
|
||||
--for the following function only:
|
||||
--for license see the link on the next line (direct permission was granted).
|
||||
--https://github.com/3dreamengine/3DreamEngine
|
||||
function rltv_point_to_hud(pos, fov, aspect)
|
||||
function Guns4d.rltv_point_to_hud(pos, fov, aspect)
|
||||
local n = .1 --near
|
||||
local f = 1000 --far
|
||||
--wherever you are
|
||||
--I WILL FOLLOWWWW YOU
|
||||
local scale = math.tan(fov * math.pi / 360)
|
||||
local r = scale * n * aspect
|
||||
local t = scale * n
|
||||
|
2
mod.conf
2
mod.conf
@ -2,4 +2,4 @@ name = guns4d
|
||||
title = guns4d
|
||||
description = Adds a library for 3d guns
|
||||
author = FatalError42O
|
||||
depends = mtul_b3d
|
||||
depends = mtul_b3d, mtul_cpml, mtul_filesystem
|
@ -1,3 +1,8 @@
|
||||
--- implements tools for quickly playing audio.
|
||||
-- @script play_sound
|
||||
|
||||
local sqrt = math.sqrt
|
||||
|
||||
--simple specification for playing a sound in relation to an action, acts as a layer of minetest.play_sound
|
||||
--"gsp" guns4d-sound-spec
|
||||
--first person for the gun holder, third person for everyone else. If first not present, third will be used.
|
||||
@ -5,8 +10,6 @@
|
||||
--example:
|
||||
--[[
|
||||
additional properties
|
||||
first_person = playername,
|
||||
second_person = playername
|
||||
sounds = { --weighted randoms:
|
||||
fire_fp = .5.
|
||||
fire_fp_2 = .2.
|
||||
@ -19,29 +22,66 @@
|
||||
gain = 1, --format for pitch and gain is interchangable.
|
||||
min_hear_distance = 20, --this is for distant gunshots, for example. Entirely optional. Cannot be used with to_player
|
||||
|
||||
exclude_player
|
||||
to_player
|
||||
--when present it automatically plays positionless audio, as this is for first person effects.
|
||||
]]
|
||||
local sqrt = math.sqrt
|
||||
function Guns4d.play_sounds(...)
|
||||
local args = {...}
|
||||
|
||||
--- defines a sound.
|
||||
-- This is passed to `minetest.sound_play` as a [ sound parameter table](https://github.com/minetest/minetest/blob/master/doc/lua_api.md#sound-parameter-table)
|
||||
-- however has the following changed or guns4d specific parameters.
|
||||
-- @field min_hear_distance this is useful if you wish to play a sound which has a "far" sound, such as distant gunshots. incompatible `with to_player`
|
||||
-- @field sounds a @{misc_helpers.weighted_randoms| weighted_randoms table} for randomly selecting sounds. The output will overwrite the `sound` field.
|
||||
-- @field to_player 4dguns changes `to_player` so it only plays positionless audio (as it is only intended for first person audio)
|
||||
-- @table guns4d_soundspec
|
||||
|
||||
local function handle_min_max(tbl)
|
||||
return tbl.min+(math.random()*(tbl.max-tbl.min))
|
||||
end
|
||||
--- allows you to play one or more sounds with more complex features, so sounds can be easily coded for guns without the need for functions.
|
||||
-- WARNING: this function modifies the tables passed to it, use `Guns4d.table.shallow_copy()` for guns4d_soundspecs
|
||||
-- @param sound_specs a @{guns4d_soundspec} or a list of @{guns4d_soundspec}s indexed my number. Also allows for shared fields. Example:
|
||||
-- {
|
||||
-- to_player = "singeplayer",
|
||||
-- min_distance = 100, --soundspec_to_play1 & soundspec_to_play2 share this parameter (as well as the to_player)
|
||||
-- soundspec_to_play1,
|
||||
-- soundspec_to_play2
|
||||
-- }
|
||||
-- @return out a list of Minetest sound handles [insert link] (in the order they came)
|
||||
-- @function Guns4d.play_sounds
|
||||
function Guns4d.play_sounds(soundspecs_list)
|
||||
--print(dump(soundspecs_list))
|
||||
--support a list of sounds to play
|
||||
if not soundspecs_list[1] then --turn into iteratable format.
|
||||
soundspecs_list = {soundspecs_list}
|
||||
end
|
||||
local applied = {}
|
||||
--all fields that aren't numbers will be copied over, allowing you to set fields across all sounds (i.e. pos, target player.), if already present it will remain the same.
|
||||
for field, v in pairs(soundspecs_list) do
|
||||
if type(field) ~= "number" then
|
||||
for _, spec in ipairs(soundspecs_list) do
|
||||
if not spec[field] then
|
||||
spec[field] = v
|
||||
end
|
||||
end
|
||||
soundspecs_list[field] = nil --so it isn't iterated
|
||||
end
|
||||
end
|
||||
--print(dump(soundspecs_list))
|
||||
local out = {}
|
||||
assert(args[1], "no arguments provided")
|
||||
for i, soundspec in pairs(args) do
|
||||
for i, soundspec in pairs(soundspecs_list) do
|
||||
assert(not (soundspec.to_player and soundspec.min_distance), "in argument '"..tostring(i).."' `min_distance` and `to_player` are incompatible parameters.")
|
||||
local sound
|
||||
local sound = soundspec.sound
|
||||
local outval
|
||||
if type(soundspec.pitch) == "table" then
|
||||
local pitch = soundspec.pitch
|
||||
soundspec.pitch = pitch.min+(math.random()*(pitch.max-pitch.min))
|
||||
for i, v in pairs(soundspec) do
|
||||
if type(v) == "table" and v.min then
|
||||
soundspec[i]=handle_min_max(v)
|
||||
end
|
||||
end
|
||||
if type(soundspec.gain) == "table" then
|
||||
local gain = soundspec.gain
|
||||
soundspec.pitch = gain.min+(math.random()*(gain.max-gain.min))
|
||||
end
|
||||
if type(soundspec.sound) == "table" then
|
||||
sound = math.weighted_randoms(soundspec.sound)
|
||||
if type(sound) == "table" then
|
||||
sound = Guns4d.math.weighted_randoms(sound)
|
||||
end
|
||||
assert(sound, "no sound found")
|
||||
if soundspec.to_player then soundspec.pos = nil end
|
||||
if soundspec.min_hear_distance then
|
||||
local exclude_player_ref
|
||||
@ -49,20 +89,28 @@ function Guns4d.play_sounds(...)
|
||||
exclude_player_ref = minetest.get_player_by_name(soundspec.exclude_player)
|
||||
end
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
soundspec.sound = nil
|
||||
local pos = player:get_pos()
|
||||
local dist = sqrt( sqrt(pos.x^2+pos.y^2)^2 +pos.z^2 )
|
||||
if (dist > soundspec.min_distance) and (player~=exclude_player_ref) then
|
||||
local dist = sqrt( sqrt((pos.x-soundspec.pos.x)^2+(pos.y-soundspec.pos.y)^2)^2 + (pos.z-soundspec.pos.z)^2)
|
||||
if (dist > soundspec.min_hear_distance) and (player~=exclude_player_ref) then
|
||||
soundspec.exclude_player = nil --not needed anyway because we can just not play it for this player.
|
||||
soundspec.to_player = player:get_player_name()
|
||||
outval = minetest.play_sound(sound, soundspec)
|
||||
outval = minetest.sound_play(sound, soundspec)
|
||||
end
|
||||
end
|
||||
else
|
||||
outval = minetest.play_sound(sound, soundspec)
|
||||
soundspec.sound = nil
|
||||
outval = minetest.sound_play(sound, soundspec)
|
||||
end
|
||||
out[i] = outval
|
||||
end
|
||||
return out
|
||||
end
|
||||
--- stops a list of sounds
|
||||
-- @param handle_list a list of minetest sound handles to stop, this is the returned output of @{guns4d.play_sounds
|
||||
-- @function Guns4d.stop_sounds
|
||||
function Guns4d.stop_sounds(handle_list)
|
||||
for i, v in pairs(handle_list) do
|
||||
minetest.sound_stop(v)
|
||||
end
|
||||
end
|
3
sounds/LICENSE ar_firing.ogg.txt
Normal file
3
sounds/LICENSE ar_firing.ogg.txt
Normal file
@ -0,0 +1,3 @@
|
||||
ar_firing.ogg:
|
||||
by SuperPhat on freesound.org
|
||||
License: Creative Commons 0
|
3
sounds/LICENSE ar_firing_far.ogg.txt
Normal file
3
sounds/LICENSE ar_firing_far.ogg.txt
Normal file
@ -0,0 +1,3 @@
|
||||
ar_firing_far.ogg:
|
||||
by (unknown) on opengameart.org (https://opengameart.org/content/the-free-firearm-sound-library)
|
||||
License: Creative Commons
|
3
sounds/LICENSE ar_mag_store.ogg.txt
Normal file
3
sounds/LICENSE ar_mag_store.ogg.txt
Normal file
@ -0,0 +1,3 @@
|
||||
ar_mag_store.ogg:
|
||||
by serøtōnin on freesound.org
|
||||
License: Creative Commons
|
0
sounds/LICENSE ar_mag_unload.ogg.txt
Normal file
0
sounds/LICENSE ar_mag_unload.ogg.txt
Normal file
BIN
sounds/ar_firing.ogg
Normal file
BIN
sounds/ar_firing.ogg
Normal file
Binary file not shown.
BIN
sounds/ar_firing_far.ogg
Normal file
BIN
sounds/ar_firing_far.ogg
Normal file
Binary file not shown.
BIN
sounds/ar_mag_load.ogg
Normal file
BIN
sounds/ar_mag_load.ogg
Normal file
Binary file not shown.
BIN
sounds/ar_mag_store.ogg
Normal file
BIN
sounds/ar_mag_store.ogg
Normal file
Binary file not shown.
BIN
sounds/ar_mag_unload.ogg
Normal file
BIN
sounds/ar_mag_unload.ogg
Normal file
Binary file not shown.
5
sounds/attribution and licensing.txt
Normal file
5
sounds/attribution and licensing.txt
Normal file
@ -0,0 +1,5 @@
|
||||
Files contained within this folder each have a respective license, their licenses are named in the following format:
|
||||
"LICENSE [file].txt"
|
||||
example:
|
||||
for ar_firing.ogg the license would be named
|
||||
"LICENSE ar_firing.ogg.txt"
|
Loading…
x
Reference in New Issue
Block a user