Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Monster weight / volume granularity #25631

Merged
merged 19 commits into from
Oct 30, 2018
Merged

Monster weight / volume granularity #25631

merged 19 commits into from
Oct 30, 2018

Conversation

nexusmrsep
Copy link
Contributor

@nexusmrsep nexusmrsep commented Sep 15, 2018

Summary

SUMMARY: Infrastructure "Converts monster size to weight and volume."

Purpose of change

Resolves #25298 Resolves #24921 Resolves #24909
Many game features use monster size classes to determine some effects. While this is a decent method for some cases, in other, like butchery, makes proper balancing impossible because lack of granularity.

Describe the solution

This PR does following things:

  • introduces weight and volume variables to monsters in mtype
  • introduces automatic conversion of volume to size class via volume_to_size method
    Conversion table below shows how middle values between existing hardcoded weights and volumes (also presented below) were used to determine delimiter (borders) between size classes.
SIZE REFERENCE CORPSE VOLUME
MS_TINY Squirrel, snake 750_ml
BORDERLINE ------------ 7500_ml
MS_SMALL Dog 30000_ml
BORDERLINE ------------- 46250_ml
MS_MEDIUM Human 62500_ml
BORDERLINE --------------- 77500_ml
MS_LARGE Cow 92500_ml
BORDERLINE -------------- 483750_ml
MS_HUGE Tank Drone 875000_ml
  • removes decoding size entries from json monster files and add decoding volume and weight from them
  • in JSON files for monsters replaces "size" with "volume" and"weight", that were set at previously hardcoded weights and volumes (presented above)
    This of course asks for a general refactor of those values according to some more sane values in many cases (example: most dogs weight over 40 kg)
  • method get_meat_chunks() that is a primary function to determine main butcher yields was redesigned to use monster's weight instead of size class. It has also been given dependency on 'meat' type to dynamically resolve number of maximum yielded items as some creatures yield not "meat" per se, but thinks like "tainted meat", "veggies", etc. that might have different weight. In general this new calculation follows @mlangsdorf idea for a function from Size / Weight / Volume of monsters granularity #25298 , but I've lowered its base value and flattened its regression, to keep it around 33% of body mass. It's final (?) form is:
    weight * ( 0.4 - 2 * ln( weight ) ) divided by mass of a proper 'meat chunk'
    Typical results in %:
WEIGHT in kg YIELD in % body mass MEAT count
1 40% 2
5 36.7% 9
10 35.3% 18
20 34% 34
50 32.1% 80
100 30.8% 154
200 29.4% 294
300 28.5% 429

This is of course dynamic, so different weights of creatures will result in granular effects.

Describe alternatives you've considered

Alternative was granulating size classes, even after introducing this PR, but a need for that would have to emerge, and there are too many places where they are uses, that would need rebalancing.

Additional context

Reference: #24909, #24921, #25244 & #25248, #24878

WARNING

  • untested - TEST BEFORE MERGING
  • will affect unsupported mods to fix their monster json files to use weight and volume instead of size

@nexusmrsep nexusmrsep added <Enhancement / Feature> New features, or enhancements on existing [JSON] Changes (can be) made in JSON [C++] Changes (can be) made in C++. Previously named `Code` Code: Infrastructure / Style / Static Analysis Code internal infrastructure and style labels Sep 15, 2018
@SunshineDistillery
Copy link
Contributor

Does it check the monster's material? Non-meat monsters should have different density/weight.

@nexusmrsep
Copy link
Contributor Author

@SunshineDistillery this is an infrastructure conversion for the starters, any re-balancing and improvement will need to be done later.

@brianlewisbeck
Copy link

mtype::get_meat_chunks() forced corpses into 5 possible sizes. All corpses of the smallest size (tiny) were 1 kg; all corpses of the next smallest size (small) were 40 kg. There is a huge gap between 1 and 40kg.

@nexusmrsep
Copy link
Contributor Author

@brianlewisbeck I have no idea what are you trying to tell here. This PR is all about changing that so... whats your point?

@brianlewisbeck
Copy link

Sorry - guess I was thinking out loud. Does the issue relate to any of the other sizes? If not, would it be possible to keep the existing framework but add subcategories to small? Seems like that would be a lot easier.

@nexusmrsep
Copy link
Contributor Author

Does the issue relate to any of the other sizes? If not, would it be possible to keep the existing framework but add subcategories to small? Seems like that would be a lot easier.

To put it simple: when coding a new monster in JSON you will be able to define its weight and volume instead of forcing it into any constraints. For example you could say your new dog breed now weights 7 kg and is 15 liters of volume. Specific in game calculations would then use that value - for example to calculate meat chunks count, or if it just needs a category of size it would use a size class like before, but that class would be calculated from the given volume - for ex. 15 liter dog falls into MS_SMALL category.

Adding subcategories is not an option now - would require to rebalance "half" of the game.

@mlangsdorf
Copy link
Contributor

is there a plan to replace the existing calls to get_size() where appropriate? Replacing the call in vehicle_move.cpp:part_collision() to critter->get_size() and the resulting switch/case set to get critter mass with get_weight(), for instance?

Or do you just plan to do this infrastructure and let the rest of us sort it out, which is fine, just want to know the plan.

@nexusmrsep
Copy link
Contributor Author

If there is an obvious function that uses get _size while it should use true weight or volume then yes. However the only one that I considered obvious was butchery yields up until now. If it would be intuitive for me to incorporate the one you mentioned then I'll try, but if not I'll pass. I will not change or balance creatures’ values either, just the infrastructure for it.

Second thing is that my free coding time got extremely scarce lately and I've got two other WIP not yet published PRs on the bench that slow me down in finishing this one. I just hope I'm closing in on finishing them.

@mlangsdorf
Copy link
Contributor

I listed every use of MS_SIZE I could find in the code in my first response in #25298. But if you're too busy, I totally understand and can clean up the vehicles code on my own after you've got this merged. Like I wrote, I don't hugely care what the answer is, I just want to know the plan. If you're only going to make the infrastructure and butchery changes, that's fine and I won't ask you to change the vehicles code if I review this PR.

@nexusmrsep
Copy link
Contributor Author

@mlangsdorf First of all thanks again for your help on fixing few issues with this PR.

I'm not too confident to touch mechanics other then butchery to translate them to weigh/volume (this would require more conceptual work to perceive the desired effect), neither have time to do it. Same for setting correct values for monsters - that might need some extra research, and involving our community would be the best approach.

So I've evaluated my take on this, and I think its best to provide this infrastructure as is to allow the community to take over from here and apply weight and volume however it's best - both in switching mechanics from size categories to actual weight/volume and also in setting individual weight and volumes for monsters in JSON files.

@nexusmrsep nexusmrsep changed the title [WIP] Monster weight / volume granularity Monster weight / volume granularity Oct 8, 2018
@nexusmrsep
Copy link
Contributor Author

I'm removing [WIP] from this PR but please TEST BEFORE MERGING.

@ZhilkinSerg ZhilkinSerg self-assigned this Oct 10, 2018
@@ -7,7 +7,8 @@
"default_faction": "",
"species": [ "ZOMBIE" ],
"diff": 100,
"size": "MEDIUM",
"volume": "62500 ml",
"weight": "81500",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not "weight": 81500 instead of "weight": "81500"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And in this I will regex quote marks into oblivion ASAP.

src/game_constants.h Outdated Show resolved Hide resolved
@@ -547,8 +548,10 @@ void mtype::load( JsonObject &jo, const std::string &src )
}

assign( jo, "color", color );
const typed_flag_reader<decltype( Creature::size_map )> size_reader{ Creature::size_map, "invalid creature size" };
optional( jo, was_loaded, "size", size, size_reader, MS_MEDIUM );
//const typed_flag_reader<decltype( Creature::size_map )> size_reader{ Creature::size_map, "invalid creature size" };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not check in commented out code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good call, didn't even noticed that I left it behind

src/mtype.cpp Outdated
@@ -52,6 +57,23 @@ std::string mtype::nname( unsigned int quantity ) const
return ngettext( name.c_str(), name_plural.c_str(), quantity );
}

m_size mtype::volume_to_size( const units::volume vol ) const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a non-static functions? It does not access any of the members of mtype, it does not needthe implicit this pointer. Make it a static function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, this requires moving it to monstergenerator.cpp, I thought it might be more universal in the future by placing it in mtype, but lets leave the future to govern itself.

src/mtype.cpp Outdated
{
if( vol > 0_ml && vol <= 7500_ml ) {
return MS_TINY;
} else if( vol > 7500_ml && vol <= 46250_ml ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need the first check, write it like this instead:

if( vol <= 7500_ml ) {
    return ...;
} else if( vol <= 46250_ml ) {
    return ...;
} else if( vol <= ...

The second if clause will only be reached if vol > 7500_ml, which does not need to be cecked again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just hope there will be no situation where vol == 0 then...

src/mtype.cpp Outdated
return 0;
float ch = units::to_gram( weight ) * ( 0.40f - 2 * log( units::to_gram( weight ) ) );
const itype *chunk = item::find_type( get_meat_itype() );
return static_cast<int>( ch / units::to_gram( chunk->weight ) );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

units:: is not needed when calling to_gram with a units::mass argument, the C++ compiler will find it anyway thanks to ADL.

@nexusmrsep
Copy link
Contributor Author

nexusmrsep commented Oct 28, 2018

Removed quote marks (") on weight and applied @BevapDin suggestions (thanks for the review). It's all yours @ZhilkinSerg.

@ZhilkinSerg
Copy link
Contributor

Great. Will test it again tonight.

@kevingranade kevingranade merged commit 3508d80 into CleverRaven:master Oct 30, 2018
@ZhilkinSerg ZhilkinSerg removed their assignment Oct 30, 2018
@GoLoT
Copy link
Contributor

GoLoT commented Oct 30, 2018

I'm not sure if this is the place or the way to report it but this commit has broken butchering completely. I can't debug because the latest experimental refuses to compile under VS but I have taken a look at the commit and I think it has to do with how the mass percent calculation is done:

float ch = to_gram( weight ) * ( 0.40f - 2 * log( to_gram( weight ) ) );
This line seems to be using weight in grams instead of kilograms which causes the calculations to be way off. The percentage calculation also seems wrong as 2*log(w) should be substracted from 40 and not 0.4, causing ch to always be a negative number and making every butcher attempt fail.

A quick fix that I can't test at the moment could be:
float ch = to_kilogram( weight ) * ( 0.40f - 0.02 * log( to_kilogram( weight ) ) );

And then divide by the chunk weight in kilograms:
return static_cast<int>( ch / to_kilogram( chunk->weight ) );

EDIT: Now that I think of it, once the percentage is calculated it can be applied to the weight in grams and the return statement doesn't need to be changed. So this should do:
float ch = to_gram( weight ) * ( 0.40f - 0.02 * log( to_kilogram( weight ) ) );

return 320;
}
return 0;
float ch = to_gram( weight ) * ( 0.40f - 2 * log( to_gram( weight ) ) );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be:

float ch = to_gram( weight ) * ( 0.40f - 0.02f * log10( to_gram( weight ) ) );

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Todo ASAP today.

@jbytheway
Copy link
Contributor

See also #26450.

@nexusmrsep nexusmrsep deleted the size_granularity branch November 2, 2018 07:58
@LyleSY LyleSY mentioned this pull request Nov 4, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[C++] Changes (can be) made in C++. Previously named `Code` Code: Infrastructure / Style / Static Analysis Code internal infrastructure and style <Enhancement / Feature> New features, or enhancements on existing [JSON] Changes (can be) made in JSON
Projects
None yet
9 participants