mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-16 18:36:43 +01:00
48d8a06d1c
This PR does a few new things: 1. Adds a Mass var for Movables (/Mob, /Obj) which is literally required for me to do anything at all with Kinematics (Very routine basic physics) 2. Adds a derived "effective mass" statistic which is generated via signal hook, allowing sources like Skills, Drugs, Cybernetics etc to pitch in and contribute to a user's "Strength" in certain situations without directly modifying mass. 3. Adds a mass modifier var for species datums, while painstakingly calibrating each and every single species with consultation from every lore team. A baseline human gets 72.0kg of Human Reference Mass. Any species applied to it will multiply this by a constant that algebraically cancels out the Human Reference Mass and replaces it with a Species Reference Mass. Changing a species via the usual procs will reset and then re-apply the correct values. 4. Refactored Lift/Drag/Fireman to have limits and penalties based on relative effective mass 5. Finally, to make use of all this, I've added a new Conditioning Skill, which modifies effective mass. The standard assumption made for Lift/Carry is based in an assumption that a typical character should realistically be able to lift/carry/fireman a person 1.25x their mass. Previously the fireman carry mechanic was heavily hardcoded, and didn't have much in the way of granularity. If I wanted to RP a character that was a bodybuilder, there wasn't really a way to do this. With this PR, there's now a fairly large variety of interesting breakpoints. This also allows there to be more granularity between different species as desired by our lore teams. For example, a Zhan is in general stronger than a M'sai. To give an example in the breakpoints for two different species: Human Lift Breakpoints: Rank 1: 90kg (lift a Skrell, Human, Offworlder, M'sai, KA, or ZA) Rank 2: 112.5kg (Lift a Zhan, Shell, or Diona Coeus) Rank 3: 135kg (Lift a (Non-Industrial) IPC, Unathi) Rank 4: 157.5kg (No new breakpoints, though you get less a movespeed penalty from lugging around any of the above) Can Never Lift: Industrial, Bullwark, Diona, Vaurca Ta' Zhan Tajara Lift Breakpoints: Rank 1: 116kg (Skrell, Human, Offworlder, M'sai, Ka, Za, Zhan, Shell, or Diona Coeus) Rank 2: 145kg (Non-Industrial IPC, Unathi) Rank 3: 174kg (No new breakpoints, though you get less penalties from the above) Rank 4: 203kg (Juuuust barely lift an Industrial or Diona with heavy slowdown) <img width="1078" height="436" alt="image" src="https://github.com/user-attachments/assets/a6802515-a827-4dc1-8734-55b604c589ab" /> Conditioning as a Skill sits in the Occupational category, which has been carefully chosen and designed around to create a fairly compelling web of opportunity costs. As a skill, it's very desireable for basically any person that wants to play a "Muscular character" and also enjoys fireman carrying people around, which makes it particularly useful for hangar techs. By contrast a Paramedic might not actually need this skill, since they can bypass the usual limits by just using rollerbeds. --------- Signed-off-by: VMSolidus <evilexecutive@gmail.com>
133 lines
5.7 KiB
Plaintext
133 lines
5.7 KiB
Plaintext
//include unit test files in this module in this ifdef
|
|
//Keep this sorted alphabetically
|
|
|
|
// #if defined(UNIT_TEST) || defined(SPACEMAN_DMM) //tgstation style, not relevant for us, for now
|
|
|
|
/// Constants indicating unit test completion status
|
|
#define UNIT_TEST_FAILED null
|
|
#define UNIT_TEST_PASSED 1
|
|
#define UNIT_TEST_SKIPPED 2 //Currently not implemented
|
|
|
|
/**
|
|
* Output colouring macros, ANSI as per https://gist.github.com/stevewithington/b1b620b5bc9252e2c32e2cad35efbf83
|
|
*/
|
|
|
|
/// Underlined Blue
|
|
#define TEST_OUTPUT_HI_BLUE(text) "\x1B\x5B0;94m[text]\x1B\x5B0m"
|
|
/// High Intensity Cyan
|
|
#define TEST_OUTPUT_U_CYAN(text) "\x1B\x5B4;36m[text]\x1B\x5B0m"
|
|
|
|
|
|
/**
|
|
* Macros used to log the Unit Test messages
|
|
*/
|
|
|
|
#define TEST_FAIL(reason) (fail(reason || "No reason", __FILE__, __LINE__))
|
|
#define TEST_PASS(reason) (pass(reason || "No reason", __FILE__, __LINE__))
|
|
|
|
/// Logs a warning message, to be used when something is important to be known to the reader, like a test that did not run,
|
|
/// but not a failure or something that necessarily indicates an issue
|
|
#define TEST_WARN(message) warn(##message, __FILE__, __LINE__)
|
|
|
|
|
|
/// Logs a notice, something that is good to be known to a scrutinizing eye, without being obnoxious
|
|
/// Do not use this with long lists or internals that most people would never care about for the vast majority of the time
|
|
#define TEST_NOTICE(message) notice(##message, __FILE__, __LINE__)
|
|
|
|
|
|
/// Logs debug messages of the test run, this is NOT normally visible in GitHub, the test has to be run in debug mode (on the GitHub actions) for that.
|
|
/// To be used to log debugging, internals information
|
|
#define TEST_DEBUG(message) debug(##message, __FILE__, __LINE__)
|
|
|
|
/// Groups management
|
|
#define TEST_GROUP_OPEN(groupname) world.log << TEST_OUTPUT_HI_BLUE("----> UNIT TEST \[[groupname]\] <----") //world.log << "::group::"+##name <-- if we want to switch back to github auto-grouping
|
|
#define TEST_GROUP_CLOSE(message) world.log << TEST_OUTPUT_HI_BLUE("\n") //world.log << ##message + "\n::endgroup::" <-- if we want to switch back to github auto-grouping
|
|
|
|
/// Asserts that a condition is true
|
|
#define TEST_ASSERT(assertion, reason) if (!(assertion)) { return fail("Assertion failed: [reason || "No reason"]", __FILE__, __LINE__) }
|
|
|
|
/// Asserts that a parameter is not null
|
|
#define TEST_ASSERT_NOTNULL(a, reason) if (isnull(a)) { return fail("Expected non-null value: [reason || "No reason"]", __FILE__, __LINE__) }
|
|
|
|
/// Asserts that a parameter is null
|
|
#define TEST_ASSERT_NULL(a, reason) if (!isnull(a)) { return fail("Expected null value but received [a]: [reason || "No reason"]", __FILE__, __LINE__) }
|
|
|
|
/// Asserts that the two parameters passed are equal
|
|
/// Optionally allows an additional message in the case of a failure
|
|
#define TEST_ASSERT_EQUAL(a, b, message) do { \
|
|
var/lhs = ##a; \
|
|
var/rhs = ##b; \
|
|
if (lhs != rhs) { \
|
|
return fail("Expected [isnull(lhs) ? "null" : lhs] to be equal to [isnull(rhs) ? "null" : rhs].[message ? " [message]" : ""]", __FILE__, __LINE__); \
|
|
} \
|
|
} while (FALSE)
|
|
|
|
/// Asserts that the two parameters passed are not equal
|
|
/// Optionally allows an additional message in the case of a failure
|
|
#define TEST_ASSERT_NOTEQUAL(a, b, message) do { \
|
|
var/lhs = ##a; \
|
|
var/rhs = ##b; \
|
|
if (lhs == rhs) { \
|
|
return fail("Expected [isnull(lhs) ? "null" : lhs] to not be equal to [isnull(rhs) ? "null" : rhs].[message ? " [message]" : ""]", __FILE__, __LINE__); \
|
|
} \
|
|
} while (FALSE)
|
|
|
|
//Temporarily just defined here
|
|
#define ANSICOLORS
|
|
|
|
/// Change color to red on ANSI terminal output, if enabled with -DANSICOLORS.
|
|
#ifdef ANSICOLORS
|
|
#define TEST_OUTPUT_RED(text) "\x1B\x5B1;31m[text]\x1B\x5B0m"
|
|
#else
|
|
#define TEST_OUTPUT_RED(text) (text)
|
|
#endif
|
|
/// Change color to green on ANSI terminal output, if enabled with -DANSICOLORS.
|
|
#ifdef ANSICOLORS
|
|
#define TEST_OUTPUT_GREEN(text) "\x1B\x5B1;32m[text]\x1B\x5B0m"
|
|
#else
|
|
#define TEST_OUTPUT_GREEN(text) (text)
|
|
#endif
|
|
/// Change color to yellow on ANSI terminal output, if enabled with -DANSICOLORS.
|
|
#ifdef ANSICOLORS
|
|
#define TEST_OUTPUT_YELLOW(text) "\x1B\x5B1;33m[text]\x1B\x5B0m"
|
|
#else
|
|
#define TEST_OUTPUT_YELLOW(text) (text)
|
|
#endif
|
|
|
|
/*
|
|
REMOVE BEFORE FLIGHT TESTING FLAGS
|
|
|
|
These all are used for physics/calculus
|
|
methods which are extremely sensitive to specific domains.
|
|
The test flags don't compile in live code, but in tests will force
|
|
test fails if the condition is not respected.
|
|
*/
|
|
#ifdef UNIT_TEST // REMOVE BEFORE FLIGHT
|
|
/**
|
|
* To be used in procs that involve calculus methods (either seconds_per_tick or delta_time).
|
|
* This enforces that said proc MUST have a valid seconds_per_tick given to it by all callers.
|
|
*/
|
|
#define ENFORCE_CALCULUS(seconds_per_tick) \
|
|
if (seconds_per_tick <= 0)\
|
|
CRASH("[caller.name] called [callee.name] without passing in seconds_per_tick (or gave a negative time). This proc MUST be given a positive and non-zero seconds_per_tick value.");
|
|
/// Test flag for forcing species mass_modifier to be a positive number.
|
|
#define ENFORCE_POSITIVE_SPECIES_MASS(mass) \
|
|
if (mass <= 0)\
|
|
CRASH("[src.type] set mass_modifier as [mass]. mass_modifier MUST BE A POSITIVE NUMBER, NOT 0 OR NEGATIVE.");
|
|
|
|
/// Test flag for forcing mass must be a positive number
|
|
#define ENFORCE_POSITIVE_MASS(mass) \
|
|
if (mass <= 0)\
|
|
CRASH("[src.type] set mass as [mass]. mass MUST BE A POSITIVE NUMBER, NOT 0 OR NEGATIVE.");
|
|
#else
|
|
/**
|
|
* To be used in procs that involve calculus methods (either seconds_per_tick or delta_time).
|
|
* This enforces that said proc MUST have a valid seconds_per_tick given to it by all callers.
|
|
*/
|
|
#define ENFORCE_CALCULUS(seconds_per_tick)
|
|
/// Test flag for forcing species mass_modifier to be a positive number.
|
|
#define ENFORCE_POSITIVE_SPECIES_MASS(mass)
|
|
/// Test flag for forcing mass must be a positive number
|
|
#define ENFORCE_POSITIVE_MASS(mass)
|
|
#endif
|