mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2025-12-14 20:22:42 +00:00
514->515 initial
adds _version.dm compatibility file + core/math/math.dm dependency adds polyvis.html tool to go along with math.dm converts uses of n_ceil to ceil
This commit is contained in:
@@ -62,3 +62,11 @@
|
||||
|
||||
//check if all bitflags specified are present
|
||||
#define CHECK_MULTIPLE_BITFIELDS(flagvar, flags) ((flagvar & (flags)) == flags)
|
||||
|
||||
|
||||
/// Right-shift of INT by BITS
|
||||
#define SHIFTR(INT, BITS) ((INT) >> (BITS))
|
||||
|
||||
|
||||
/// Left-shift of INT by BITS
|
||||
#define SHIFTL(INT, BITS) ((INT) << (BITS))
|
||||
|
||||
69
code/_version.dm
Normal file
69
code/_version.dm
Normal file
@@ -0,0 +1,69 @@
|
||||
#if DM_VERSION < 515
|
||||
|
||||
#define call_ext(ARGS...) call(ARGS)
|
||||
|
||||
/proc/ceil(number)
|
||||
return -round(-number)
|
||||
|
||||
/proc/floor(number)
|
||||
return round(number)
|
||||
|
||||
/proc/fract(number)
|
||||
return number - trunc(number)
|
||||
|
||||
/proc/ftime()
|
||||
throw EXCEPTION("ftime not available below 515")
|
||||
|
||||
/proc/get_steps_to()
|
||||
throw EXCEPTION("get_steps_to not available below 515")
|
||||
|
||||
/proc/isinf(number)
|
||||
return number == POSITIVE_INFINITY || number == NEGATIVE_INFINITY
|
||||
|
||||
/proc/isnan(number)
|
||||
return isnum(number) && number != number
|
||||
|
||||
/proc/ispointer()
|
||||
throw EXCEPTION("ispointer not available below 515")
|
||||
|
||||
/proc/nameof(thing)
|
||||
throw EXCEPTION("nameof not available below 515")
|
||||
|
||||
/proc/noise_hash()
|
||||
throw EXCEPTION("noise_hash not available below 515")
|
||||
|
||||
/proc/refcount(datum)
|
||||
throw EXCEPTION("refcount not available below 515")
|
||||
|
||||
/proc/trimtext(text)
|
||||
var/static/regex/pattern
|
||||
if (!pattern)
|
||||
pattern = regex(@"^\s*(.*?)\s*$", "g")
|
||||
return replacetext_char(text, pattern, "$1")
|
||||
|
||||
/proc/trunc(number)
|
||||
if (number < 0)
|
||||
return -round(-number)
|
||||
return round(number)
|
||||
|
||||
/client/proc/RenderIcon(atom)
|
||||
throw EXCEPTION("client::RenderIcon() not available below 515")
|
||||
|
||||
/* lists cannot have new procs. But if they could:
|
||||
/list/proc/RemoveAll()
|
||||
var/result = 0
|
||||
for (var/entry in args)
|
||||
while (Remove(entry))
|
||||
++result
|
||||
return result
|
||||
*/
|
||||
|
||||
#define ANIMATION_SLICE 8
|
||||
#define ANIMATION_CONTINUE 512
|
||||
|
||||
#define JSON_PRETTY_PRINT 1
|
||||
|
||||
#define JSON_STRICT 1
|
||||
#define JSON_ALLOW_COMMENTS 2
|
||||
|
||||
#endif
|
||||
119
code/core/math/math.dm
Normal file
119
code/core/math/math.dm
Normal file
@@ -0,0 +1,119 @@
|
||||
/// IEEE 754-1985 positive infinity. As text, win: 1.#INF, lin: inf
|
||||
var/global/const/POSITIVE_INFINITY = 1#INF
|
||||
|
||||
/// IEEE 754-1985 negative infinity. As text, win: -1.#INF, -lin: inf
|
||||
var/global/const/NEGATIVE_INFINITY = -1#INF
|
||||
|
||||
// IEEE 754-1985 positive NaN. Creatable but not useful. As text, win: 1.#QNAN, lin: nan
|
||||
//var/const/POSITIVE_NAN = -(1#INF/1#INF)
|
||||
|
||||
// IEEE 754-1985 nevative NaN. Creatable but not useful. As text, win: -1.#IND, lin: -nan
|
||||
//var/const/NEGATIVE_NAN = (1#INF/1#INF)
|
||||
|
||||
/// Multiplier for converting degrees to radians, rounded to 10 places
|
||||
var/global/const/DEG_TO_RAD = 0.0174532925
|
||||
|
||||
/// Multiplier for converting radians to degrees, rounded to 10 places
|
||||
var/global/const/RAD_TO_DEG = 57.295779513
|
||||
|
||||
/// The mathematical constant pi, rounded to 10 places
|
||||
var/global/const/PI = 3.1415926536
|
||||
|
||||
/// Twice the mathematical constant pi, rounded to 10 places
|
||||
var/global/const/TWO_PI = 6.2831853072
|
||||
|
||||
/// Half the mathematical constant pi, rounded to 10 places
|
||||
var/global/const/HALF_PI = 1.5707963268
|
||||
|
||||
|
||||
/// True if number is a number that is not nan or an infinity.
|
||||
/proc/isfinite(number)
|
||||
return isnum(number) && !isnan(number) && !isinf(number)
|
||||
|
||||
|
||||
/**
|
||||
Sample t(0..1) into a quadratic binomial polynomial.
|
||||
Generally this is useful for shaping rand() distribution.
|
||||
see tools/polyvis.html for a parameter picker.
|
||||
*/
|
||||
/proc/poly_interp2(t, p0, p1, p2)
|
||||
var/mt = 1 - t
|
||||
return p0 * mt * mt +\
|
||||
2 * p1 * mt * t +\
|
||||
p2 * t * t
|
||||
|
||||
/**
|
||||
Sample t(0..1) into a cubic binomial polynomial.
|
||||
Generally this is useful for shaping rand() distribution.
|
||||
see tools/polyvis.html for a parameter picker.
|
||||
More expensive than poly_interp2.
|
||||
*/
|
||||
/proc/poly_interp3(t, p0, p1, p2, p3)
|
||||
var/t2 = t * t
|
||||
var/mt = 1 - t
|
||||
var/mt2 = mt * mt
|
||||
return p0 * mt2 * mt +\
|
||||
3 * p1 * mt2 * t +\
|
||||
3 * p2 * mt * t2 +\
|
||||
p3 * t2 * t
|
||||
|
||||
/**
|
||||
Sample t(0..1) into a quartic binomial polynomial.
|
||||
Generally this is useful for shaping rand() distribution.
|
||||
see tools/polyvis.html for a parameter picker.
|
||||
More expensive than poly_interp3.
|
||||
*/
|
||||
/proc/poly_interp4(t, p0, p1, p2, p3, p4)
|
||||
var/t2 = t * t
|
||||
var/t3 = t2 * t
|
||||
var/mt = 1 - t
|
||||
var/mt2 = mt * mt
|
||||
var/mt3 = mt2 * mt
|
||||
return p0 * mt3 * mt +\
|
||||
4 * p1 * mt3 * t +\
|
||||
6 * p2 * mt2 * t2 +\
|
||||
4 * p3 * mt * t3 +\
|
||||
p4 * t3 * t
|
||||
|
||||
|
||||
/**
|
||||
Get the coordinates that make up a circle of radius on center, packed as (x | y left shift 12).
|
||||
These coordinates are able to be outside the world: check (v < 1 || v > world.maxV) for safety.
|
||||
Implements the Bresenham Circle Drawing Algorithm for the actual point picking.
|
||||
*/
|
||||
/proc/get_circle_coordinates(radius, center_x, center_y)
|
||||
var/static/list/cache = list()
|
||||
radius = round(radius, 1)
|
||||
if (radius < 1)
|
||||
return list(center_x | SHIFTL(center_y, 12))
|
||||
center_x = round(center_x, 1)
|
||||
center_y = round(center_y, 1)
|
||||
var/list/points = length(cache) ? cache["[radius]"] : null
|
||||
if (!points)
|
||||
points = list()
|
||||
var/y = radius
|
||||
var/gradient = 3 - 2 * radius
|
||||
for (var/x = 0 to radius)
|
||||
points |= list(
|
||||
radius + x | SHIFTL(radius + y, 12),
|
||||
radius + x | SHIFTL(radius - y, 12),
|
||||
radius - x | SHIFTL(radius + y, 12),
|
||||
radius - x | SHIFTL(radius - y, 12),
|
||||
radius + y | SHIFTL(radius + x, 12),
|
||||
radius + y | SHIFTL(radius - x, 12),
|
||||
radius - y | SHIFTL(radius + x, 12),
|
||||
radius - y | SHIFTL(radius - x, 12)
|
||||
)
|
||||
if (x >= y)
|
||||
break
|
||||
if (gradient < 0)
|
||||
gradient = gradient + 4 * x + 6
|
||||
else
|
||||
gradient = gradient + 4 * (x - y) + 10
|
||||
--y
|
||||
cache["[radius]"] = points
|
||||
var/list/result = points.Copy()
|
||||
var/center = center_x - radius | SHIFTL(center_y - radius, 12)
|
||||
for (var/i = 1 to length(result))
|
||||
result[i] += center
|
||||
return result
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
name = lowertext("[fullname] sandwich")
|
||||
if(length(name) > 80) name = "[pick(list("absurd","colossal","enormous","ridiculous"))] sandwich"
|
||||
w_class = n_ceil(clamp((ingredients.len/2),2,4))
|
||||
w_class = ceil(clamp((ingredients.len/2),2,4))
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/csandwich/Destroy()
|
||||
for(var/obj/item/O in ingredients)
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
/datum/random_map/droppod/generate_map()
|
||||
|
||||
// No point calculating these 200 times.
|
||||
var/x_midpoint = n_ceil(limit_x / 2)
|
||||
var/y_midpoint = n_ceil(limit_y / 2)
|
||||
var/x_midpoint = ceil(limit_x / 2)
|
||||
var/y_midpoint = ceil(limit_y / 2)
|
||||
|
||||
// Draw walls/floors/doors.
|
||||
for(var/x = 1, x <= limit_x, x++)
|
||||
@@ -80,7 +80,7 @@
|
||||
|
||||
/datum/random_map/droppod/apply_to_map()
|
||||
if(placement_explosion_dev || placement_explosion_heavy || placement_explosion_light || placement_explosion_flash)
|
||||
var/turf/T = locate((origin_x + n_ceil(limit_x / 2)-1), (origin_y + n_ceil(limit_y / 2)-1), origin_z)
|
||||
var/turf/T = locate((origin_x + ceil(limit_x / 2)-1), (origin_y + ceil(limit_y / 2)-1), origin_z)
|
||||
if(istype(T))
|
||||
explosion(T, placement_explosion_dev, placement_explosion_heavy, placement_explosion_light, placement_explosion_flash)
|
||||
sleep(15) // Let the explosion finish proccing before we ChangeTurf(), otherwise it might destroy our spawned objects.
|
||||
@@ -97,8 +97,8 @@
|
||||
|
||||
// Pods are circular. Get the direction this object is facing from the center of the pod.
|
||||
/datum/random_map/droppod/get_spawn_dir(var/x, var/y)
|
||||
var/x_midpoint = n_ceil(limit_x / 2)
|
||||
var/y_midpoint = n_ceil(limit_y / 2)
|
||||
var/x_midpoint = ceil(limit_x / 2)
|
||||
var/y_midpoint = ceil(limit_y / 2)
|
||||
if(x == x_midpoint && y == y_midpoint)
|
||||
return null
|
||||
var/turf/target = locate(origin_x+x-1, origin_y+y-1, origin_z)
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
/datum/random_map/meteor/generate_map()
|
||||
|
||||
// No point calculating these 200 times.
|
||||
var/x_midpoint = n_ceil(limit_x / 2)
|
||||
var/y_midpoint = n_ceil(limit_y / 2)
|
||||
var/x_midpoint = ceil(limit_x / 2)
|
||||
var/y_midpoint = ceil(limit_y / 2)
|
||||
|
||||
// Draw walls/floors
|
||||
for(var/x = 1, x <= limit_x, x++)
|
||||
@@ -72,7 +72,7 @@
|
||||
if(!applied)
|
||||
applied = TRUE
|
||||
if(placement_explosion_dev || placement_explosion_heavy || placement_explosion_light || placement_explosion_flash)
|
||||
var/turf/T = locate((origin_x + n_ceil(limit_x / 2)-1), (origin_y + n_ceil(limit_y / 2)-1), origin_z)
|
||||
var/turf/T = locate((origin_x + ceil(limit_x / 2)-1), (origin_y + ceil(limit_y / 2)-1), origin_z)
|
||||
if(istype(T))
|
||||
explosion(T, placement_explosion_dev, placement_explosion_heavy, placement_explosion_light, placement_explosion_flash)
|
||||
sleep(15) // Let the explosion finish proccing before we ChangeTurf(), otherwise it might destroy our spawned objects.
|
||||
@@ -89,8 +89,8 @@
|
||||
|
||||
// Meteors are circular. Get the direction this object is facing from the center of the pod.
|
||||
/datum/random_map/meteor/get_spawn_dir(var/x, var/y)
|
||||
var/x_midpoint = n_ceil(limit_x / 2)
|
||||
var/y_midpoint = n_ceil(limit_y / 2)
|
||||
var/x_midpoint = ceil(limit_x / 2)
|
||||
var/y_midpoint = ceil(limit_y / 2)
|
||||
if(x == x_midpoint && y == y_midpoint)
|
||||
return null
|
||||
var/turf/target = locate(origin_x+x-1, origin_y+y-1, origin_z)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "code\_macros.dm"
|
||||
#include "code\_map_tests.dm"
|
||||
#include "code\_unit_tests.dm"
|
||||
#include "code\_version.dm"
|
||||
#include "code\global.dm"
|
||||
#include "code\global_init.dm"
|
||||
#include "code\hub.dm"
|
||||
@@ -266,6 +267,7 @@
|
||||
#include "code\core\atom\Transform.dm"
|
||||
#include "code\core\datum\IsAbstract.dm"
|
||||
#include "code\core\image\Transform.dm"
|
||||
#include "code\core\math\math.dm"
|
||||
#include "code\core\matrix\Transform.dm"
|
||||
#include "code\datums\ai_law_sets.dm"
|
||||
#include "code\datums\ai_laws.dm"
|
||||
|
||||
168
tools/polyvis.html
Normal file
168
tools/polyvis.html
Normal file
@@ -0,0 +1,168 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>cbrand picker</title>
|
||||
<style>
|
||||
html, body {
|
||||
background-color: #222;
|
||||
color: #eee;
|
||||
}
|
||||
</style>
|
||||
<script type="module">
|
||||
|
||||
const quadratic_interp = (t, p0, p1, p2) => {
|
||||
const mt = 1 - t
|
||||
return p0 * mt * mt +
|
||||
2 * p1 * mt * t +
|
||||
p2 * t * t
|
||||
}
|
||||
|
||||
const cubic_interp = (t, p0, p1, p2, p3) => {
|
||||
const t2 = t * t
|
||||
const mt = 1 - t
|
||||
const mt2 = mt * mt
|
||||
return p0 * mt2 * mt +
|
||||
3 * p1 * mt2 * t +
|
||||
3 * p2 * mt * t2 +
|
||||
p3 * t2 * t
|
||||
}
|
||||
|
||||
const quartic_interp = (t, p0, p1, p2, p3, p4) => {
|
||||
const t2 = t * t
|
||||
const t3 = t2 * t
|
||||
const mt = 1 - t
|
||||
const mt2 = mt * mt
|
||||
const mt3 = mt2 * mt
|
||||
return p0 * mt3 * mt +
|
||||
4 * p1 * mt3 * t +
|
||||
6 * p2 * mt2 * t2 +
|
||||
4 * p3 * mt * t3 +
|
||||
p4 * t3 * t
|
||||
}
|
||||
|
||||
const random_iterations = 1e5
|
||||
|
||||
const ctx = document.querySelector('canvas').getContext('2d')
|
||||
const out = document.querySelector('#out')
|
||||
|
||||
const inputs = [ ...document.querySelectorAll('input[type="range"]') ]
|
||||
.reduce(function (inputs, input) {
|
||||
inputs[input.id] = input
|
||||
return inputs
|
||||
}, {})
|
||||
|
||||
let interp_func = quadratic_interp
|
||||
let procname = 'interp2'
|
||||
|
||||
const funcSelector = document.querySelector('select')
|
||||
|
||||
funcSelector.addEventListener('change', updateInterpFunc)
|
||||
|
||||
function updateInterpFunc () {
|
||||
if (funcSelector.value === 'quadratic') {
|
||||
inputs['p4y'].setAttribute('hidden', true)
|
||||
inputs['p5y'].setAttribute('hidden', true)
|
||||
interp_func = quadratic_interp
|
||||
procname = 'poly_interp2'
|
||||
}
|
||||
else if (funcSelector.value === 'cubic') {
|
||||
inputs['p4y'].removeAttribute('hidden')
|
||||
inputs['p5y'].setAttribute('hidden', true)
|
||||
interp_func = cubic_interp
|
||||
procname = 'poly_interp3'
|
||||
}
|
||||
else {
|
||||
inputs['p4y'].removeAttribute('hidden')
|
||||
inputs['p5y'].removeAttribute('hidden')
|
||||
interp_func = quartic_interp
|
||||
procname = 'poly_interp4'
|
||||
}
|
||||
}
|
||||
|
||||
function getInput (...ids) {
|
||||
return ids.map(id => Number.parseFloat(inputs[id].value))
|
||||
}
|
||||
|
||||
function getInputY () {
|
||||
return getInput('p1y', 'p2y', 'p3y', 'p4y', 'p5y')
|
||||
}
|
||||
|
||||
updateInterpFunc()
|
||||
|
||||
let lastInputs
|
||||
|
||||
requestAnimationFrame(function frame() {
|
||||
requestAnimationFrame(frame)
|
||||
let inputs = getInputY()
|
||||
let sig = inputs.join() + funcSelector.value
|
||||
if (sig === lastInputs)
|
||||
return
|
||||
lastInputs = sig
|
||||
const { clientWidth: w, clientHeight: h } = ctx.canvas
|
||||
ctx.strokeStyle = 'black'
|
||||
ctx.fillStyle = 'black'
|
||||
ctx.fillRect(0,0,w,h)
|
||||
const [ y1, y2, y3, y4 ] = inputs
|
||||
ctx.strokeStyle = 'dodgerblue'
|
||||
ctx.lineWidth = 1.0
|
||||
ctx.fillStyle = 'dodgerblue'
|
||||
const results = new Array(101).fill(0)
|
||||
for (let i = 1; i < random_iterations; ++i)
|
||||
++results[Math.round(interp_func(Math.random(), ...inputs) * 100)]
|
||||
let lowest = 100
|
||||
let highest = 0
|
||||
let mode = 0
|
||||
let mode_val = 0
|
||||
for (let i = 0; i <= 100; ++i) {
|
||||
let val = results[i]
|
||||
if (!val)
|
||||
continue
|
||||
if (val > mode_val) {
|
||||
mode = i
|
||||
mode_val = val
|
||||
}
|
||||
if (i < lowest)
|
||||
lowest = i
|
||||
if (i > highest)
|
||||
highest = i
|
||||
}
|
||||
for (let i = lowest; i <= highest; ++i) {
|
||||
let val = results[i]
|
||||
ctx.fillRect(w, h - i * 0.01 * h, -((val / mode_val) * (w / 2)), h * 0.01)
|
||||
}
|
||||
ctx.strokeStyle = 'darkred'
|
||||
ctx.lineWidth = 4.0
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(0, h - inputs[0] * h)
|
||||
for (let i = 1; i <= 100; ++i)
|
||||
ctx.lineTo(i / 100 * w, h - interp_func(i / 100, ...inputs) * h)
|
||||
ctx.stroke()
|
||||
ctx.strokeStyle = 'white'
|
||||
ctx.lineWidth = 1.0
|
||||
ctx.strokeText(`${(highest/100).toFixed(2)}`, w/2 - 40, h - (highest * 0.01 * h) + 12)
|
||||
ctx.strokeText(`${(lowest/100).toFixed(2)}`, w/2 - 40, h - (lowest * 0.01 * h) - 12)
|
||||
ctx.strokeStyle = 'green'
|
||||
ctx.strokeRect(0, 0, w, h)
|
||||
out.innerText = `${procname}(${inputs.join(', ')}, rand())`
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<select>
|
||||
<option value="quadratic">quadratic</option>
|
||||
<option value="cubic">cubic</option>
|
||||
<option value="quartic">quartic</option>
|
||||
</select>
|
||||
<p><input id="p1y" type="range" min="0" max="1" step="0.01" value="0"></p>
|
||||
<p><input id="p2y" type="range" min="0" max="1" step="0.01" value="0.8"></p>
|
||||
<p><input id="p3y" type="range" min="0" max="1" step="0.01" value="0.2"></p>
|
||||
<p><input id="p4y" type="range" min="0" max="1" step="0.01" value="1"></p>
|
||||
<p><input id="p5y" type="range" min="0" max="1" step="0.01" value="1"></p>
|
||||
<p>red line: the sample curve.</p>
|
||||
<p>blue bars: the distribution, given random 0..1 numbers.</p>
|
||||
<p>white numbers: rough min/max values possible.</p>
|
||||
<p>dm call: <span id="out"></span></p>
|
||||
<p><canvas id="shape" width="500" height="500"></canvas></p>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user