Skip to content
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d751924
introduce advanced tax & wage contribution logic
zd-k Jan 12, 2025
e8eb3f8
replace & with and word
zd-k Jan 12, 2025
1bc7bef
introduce faster sentiment drop, refactoring
zd-k Jan 13, 2025
51fde7b
add missed ini key entry
zd-k Jan 14, 2025
04c5d91
move advanced tax and wage logic to difficulty tab
zd-k Jan 14, 2025
618838e
add faster sentiment gain, new gain/loss logic is enabled only after …
zd-k Jan 14, 2025
9a7f864
adjust gain/drop modifiers by difficulty
zd-k Jan 16, 2025
dc46c8b
make changes to the comments
zd-k Jan 16, 2025
91135dc
fix example #2 in explanation comment
zd-k Jan 16, 2025
57a99e0
add new sentiment change logic cooldown for newly built houses
zd-k Jan 16, 2025
4979e7e
prevent compile warning by add a name to union (extra_attr) which sha…
zd-k Jan 16, 2025
f154f23
fix an issue with storage_id for buildings which are not storage kind
zd-k Jan 16, 2025
2e34ea6
Merge branch 'master' of github.com:ZelionD/augustus into feature/adv…
zd-k Jan 16, 2025
990456a
move advanced sentiment variable to it's own property and bump save f…
zd-k Jan 17, 2025
ebdaa02
Merge branch 'master' of github.com:ZelionD/augustus into feature/adv…
zd-k Jan 17, 2025
a45a2f8
revert cross-compilation changes accidentally commited
zd-k Jan 17, 2025
58eebdf
fix load order from file
zd-k Jan 21, 2025
59c1c30
name struct advanced_sentiment
zd-k Jan 21, 2025
c834aad
simplify a logic for gain/loss sentiment points, lower punishment
zd-k Jan 22, 2025
17db04d
update examples for gain/loss house happiness
zd-k Jan 22, 2025
1950d23
Merge branch 'master' of github.com:ZelionD/augustus into feature/adv…
zd-k Jan 23, 2025
f9e1f11
Merge branch 'master' of github.com:ZelionD/augustus into feature/adv…
zd-k Feb 3, 2025
db4c714
apply suggestions
zd-k Feb 3, 2025
cc909fe
rename building_is_storage_kind to building_uses_storage
zd-k Feb 3, 2025
8993c5c
remove redundant comment
zd-k Feb 3, 2025
d7bbfb7
apply suggestion for population check instead of months
zd-k Feb 3, 2025
5876bde
make wage interval a preprocessor definition
zd-k Feb 3, 2025
4e8dff6
add early return for case when wages set to exactly the same amount R…
zd-k Feb 3, 2025
a5e5c5d
replace shr by div
zd-k Feb 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion src/building/building.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@ static void remove_adjacent_types(building *b)
b->next_of_type = 0;
}

void initialize_sentiment_cooldown(building *b) {
if (b->house_adv_sentiment.cooldown_initialized) {
return;
}

b->house_adv_sentiment.cooldown_initialized = 1;

if (b->type <= BUILDING_HOUSE_GRAND_INSULA) {
b->house_adv_sentiment.cooldown = ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS;
} else {
// Do not apply cooldown to villas
b->house_adv_sentiment.cooldown = 0;
}
}

building *building_create(building_type type, int x, int y)
{
building *b;
Expand Down Expand Up @@ -205,6 +220,7 @@ building *building_create(building_type type, int x, int y)

// subtype
if (building_is_house(type)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if (building_is_house(type)) {
if (building_is_house(type) && b->subtype.house_level < HOUSE_SMALL_VILLA) {

I think this would be more readable and not require the check in the function.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Which check are you referring to?

int building_is_house(building_type type)
{
    return type >= BUILDING_HOUSE_VACANT_LOT && type <= BUILDING_HOUSE_LUXURY_PALACE;
}

It has nothing to the check of villa house, just a generic housing. Also in that if branch there is also an assignment b->subtype.house_level = type - BUILDING_HOUSE_VACANT_LOT; which will stop working for villas with your suggestion. If you're referring to a initialize_sentiment_cooldown, then probably function could be removed, since you didn't like the initialized flag, probably it could be removed in favor of checking save file version instead.

initialize_sentiment_cooldown(b);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not sure you need the function. The cooldown ticks should only be set when the building is actually created (right here in this function), then they'll slowly go down when there are people in the house.

For removing cooldowns from villas, just set the ticks to 0 when they upgrade in house_evolution.

b->subtype.house_level = type - BUILDING_HOUSE_VACANT_LOT;
}

Expand Down Expand Up @@ -268,7 +284,7 @@ static void building_delete(building *b)

void building_clear_related_data(building *b)
{
if (b->storage_id) {
if (building_is_storage_kind(b->type) && b->storage_id) {
building_storage_delete(b->storage_id);
b->storage_id = 0;
}
Expand Down Expand Up @@ -424,6 +440,11 @@ int building_is_house(building_type type)
return type >= BUILDING_HOUSE_VACANT_LOT && type <= BUILDING_HOUSE_LUXURY_PALACE;
}

int building_is_storage_kind(building_type type)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
int building_is_storage_kind(building_type type)
int building_uses_storage(building_type type)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Not sure if the suggested naming is somehow better than proposed in the PR.

{
return type == BUILDING_WAREHOUSE || type == BUILDING_GRANARY;
}

// For Venus GT base bonus
int building_is_statue_garden_temple(building_type type)
{
Expand Down
26 changes: 26 additions & 0 deletions src/building/building.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,27 @@
#include "game/resource.h"
#include "translation/translation.h"

// Ticks of cooldown before new advanced sentiment logic will be applied
// for the house building. Each tick is equal to 3 months. That value
// shouldn't ever exceed 7, since it takes 3 bits of data.
// To extend or reduce the cooldown duration edit the
// ADVANCED_SENTIMENT_COOLDOWN_TICK_MONTHS preprocessor definition.
#define ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS 7
#define ADVANCED_SENTIMENT_COOLDOWN_TICK_MONTHS 3

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Wouldn't it just be simpler to use one tick per month and increase max ticks?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

If use an int, then yes, but as I replied above, there will be no room for improvements without breaking changes to save files. The initial idea was to re-use existing byte of data previously not used by houses, however it then were moved to it's own memory


typedef enum order_condition_type {
ORDER_CONDITION_NEVER = 0,
ORDER_CONDITION_ALWAYS,
ORDER_CONDITION_SOURCE_HAS_MORE_THAN,
ORDER_CONDITION_DESTINATION_HAS_LESS_THAN
} order_condition_type;

typedef struct advanced_sentiment {
uint8_t cooldown_initialized: 1;
uint8_t cooldown: 3;
uint8_t reserved: 4;
} advanced_sentiment;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please, no bitfields. Just use plain ints in the house structure. We're not starved for memory.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

That were done under the purpose of potential improvements to keep compatibility with versions without making a breaking change. By using int, no more future improvements which could require some bit flags possible without incrementing the save version

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Frankly I don't think it's worth it. We're saving just 4 bits and then we'll need a version bump anyway. And I'd really prefer to use a whole int, even if wasteful.

I mean if you want to save some savegame bytes for later you might as well reserve them now, if we do bump the savegame version.


typedef struct order {
resource_type resource_type;
int src_storage_id;
Expand Down Expand Up @@ -180,6 +194,11 @@ typedef struct building {
signed char house_happiness;
signed char native_anger;
} sentiment;
// New advanced sentiment contribution logic requires cooldown for newly built houses.
// The new happiness gain/drop logic will not be applied until cooldown expires.
// Cooldown ticks get decreased every Jan/Apr/Jul/Oct, which gives 18-20 months in total.
// That should be enough to build new housing block and evolve it.
struct advanced_sentiment house_adv_sentiment;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// New advanced sentiment contribution logic requires cooldown for newly built houses.
// The new happiness gain/drop logic will not be applied until cooldown expires.
// Cooldown ticks get decreased every Jan/Apr/Jul/Oct, which gives 18-20 months in total.
// That should be enough to build new housing block and evolve it.
struct advanced_sentiment house_adv_sentiment;
int sentiment_cooldown_ticks;

No need to call it advanced or anything 😉 Also, I think only the actual ticks are needed. See above.

Also, the explanation of the mechanics can stay on the sentiment.c side of things.

unsigned char show_on_problem_overlay;
unsigned char house_tavern_wine_access;
unsigned char house_tavern_food_access;
Expand Down Expand Up @@ -220,6 +239,8 @@ building *building_main(building *b);

building *building_next(building *b);

void initialize_sentiment_cooldown(building *b);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

As mentioned above, I don't think this function is needed.

But if it was needed, since it is a public function, it should be declared as building_initialize_sentiment_cooldown, so it has a sort of namespace to allow users to better understand what the function is related to and where it may be located in the source.

building *building_create(building_type type, int x, int y);

void building_clear_related_data(building *b);
Expand All @@ -232,6 +253,11 @@ void building_update_state(void);

void building_update_desirability(void);

/**
* Checks if building can store goods
*/
int building_is_storage_kind(building_type type);

int building_is_house(building_type type);

int building_is_ceres_temple(building_type type);
Expand Down
28 changes: 27 additions & 1 deletion src/building/state.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "state.h"

#include <assert.h>

Comment on lines +3 to +4

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Remove include. See below.

#include "building/industry.h"
#include "building/monument.h"
#include "building/roadblock.h"
Expand Down Expand Up @@ -164,6 +166,14 @@ void building_state_save_to_buffer(buffer *buf, const building *b)
buffer_write_u8(buf, b->is_adjacent_to_water);
buffer_write_u8(buf, b->storage_id);
buffer_write_i8(buf, b->sentiment.house_happiness); // which union field we use does not matter

assert (sizeof(b->house_adv_sentiment) == sizeof(uint8_t));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No need for the assert here really.

if (building_is_house(b->type)) {
buffer_write_raw(buf, &b->house_adv_sentiment, sizeof(b->house_adv_sentiment));
} else {
buffer_skip(buf, sizeof(b->house_adv_sentiment));
}
Comment on lines +171 to +174

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I understand your change here, however, I try to avoid bumping the savegame version as much as I can.

You have a line above (line 144) with the following code:

buffer_write_i16(buf, 0);

This means you have two bytes of unused space there, which you can use to store the cooldown ticks.

So I'd replace that line with:

buffer_write_i16(buf, sentiment_cooldown_ticks);

Yes the variable is being converted from a 32-bit int to a 16-bit int, but I hardly think we'll need more than 32767 ticks anyway.


buffer_write_u8(buf, b->show_on_problem_overlay);

// expanded building data
Expand Down Expand Up @@ -486,8 +496,20 @@ void building_state_load_from_buffer(buffer *buf, building *b, int building_buf_
b->desirability = buffer_read_i8(buf);
b->is_deleted = buffer_read_u8(buf);
b->is_adjacent_to_water = buffer_read_u8(buf);
b->storage_id = buffer_read_u8(buf);
if (building_is_storage_kind(b->type)) {
b->storage_id = buffer_read_u8(buf);
} else {
b->storage_id = 0;
buffer_skip(buf, 1); // do not load storage_id for non-storage buildings

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No need for the comment, the code is self explanatory.

As a matter of fact, comments should be avoided unless you can't really understand what's going on by just looking at the code. That forces you to improve code readability, which in turn is better for other coders to understand what's going on. See below for an example where your comments are a good idea.

Other than that, I agree with this particular change. This will avoid weird corruptions in the future.

}
b->sentiment.house_happiness = buffer_read_i8(buf); // which union field we use does not matter
if (save_version >= SAVE_GAME_LAST_ADVANCED_SENTIMENT) {
if (building_is_house(b->type)) {
buffer_read_raw(buf, &b->house_adv_sentiment, sizeof(b->house_adv_sentiment));
} else {
buffer_skip(buf, sizeof(b->house_adv_sentiment));
}
}
Comment on lines +506 to +511

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

As mentioned above, you can use the two free bytes.

You may notice that on line 476 the bytes are being used to store a variable loads_stored.

However that variable is only set to a value other than 0 is save_version is at or below SAVE_GAME_LAST_NO_NEW_MONUMENT_RESOURCES. That means you can safely use the two bytes for both purposes.

So you can set line 476 to the following:

int loads_stored = 0;
if (save_version <= SAVE_GAME_LAST_NO_NEW_MONUMENT_RESOURCES) {
    loads_stored = buffer_read_i16(buf);
} else {
    b->sentiment_cooldown = buffer_read_i16(buf);
}

That way you can use that value and avoid bumping the savegame version.

b->show_on_problem_overlay = buffer_read_u8(buf);

// Wharves produce fish and don't need any progress
Expand Down Expand Up @@ -687,4 +709,8 @@ void building_state_load_from_buffer(buffer *buf, building *b, int building_buf_
if (building_buf_size > BUILDING_STATE_CURRENT_BUFFER_SIZE) {
buffer_skip(buf, building_buf_size - BUILDING_STATE_CURRENT_BUFFER_SIZE);
}

if (building_is_house(b->type)) {
initialize_sentiment_cooldown(b);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I really don't think this is needed. This will reinitialize the sentiment cooldown to ongoing cities that are loaded, which I don't think is needed or even recommended. Worse, it will allow exploits by saving/reloading the cities.

}
5 changes: 3 additions & 2 deletions src/building/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
#define BUILDING_STATE_TOURISM_BUFFER_SIZE (BUILDING_STATE_ORIGINAL_BUFFER_SIZE + 6) // 134
#define BUILDING_STATE_VARIANTS_AND_UPGRADES (BUILDING_STATE_TOURISM_BUFFER_SIZE + 2) // 136
#define BUILDING_STATE_STRIKES (BUILDING_STATE_VARIANTS_AND_UPGRADES + 1) // 137
#define BUILDING_STATE_SICKNESS (BUILDING_STATE_STRIKES + 5) // 142
#define BUILDING_STATE_WITHOUT_RESOURCES (BUILDING_STATE_SICKNESS - RESOURCE_MAX_LEGACY) // 126 (plus variable resource size)
#define BUILDING_STATE_ADV_SENTIMENT (BUILDING_STATE_STRIKES + sizeof(advanced_sentiment)) // 138

@Keriew Keriew Jan 26, 2025

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

These defines here are used for the purpose of backward compatibility, the state where we actually have the newly added values never happened, so any additions to the size should be at the end of the segment.

#define BUILDING_STATE_SICKNESS (BUILDING_STATE_ADV_SENTIMENT + 5) // 143
#define BUILDING_STATE_WITHOUT_RESOURCES (BUILDING_STATE_SICKNESS - RESOURCE_MAX_LEGACY) // 127 (plus variable resource size)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

By not adding bytes to the savefile, you don't need to bump the version and you also don't need these defines.

#define BUILDING_STATE_DYNAMIC_RESOURCES (BUILDING_STATE_WITHOUT_RESOURCES + BUILDING_STATE_NONSTATIC_RESOURCE_SIZE)
#define BUILDING_STATE_CURRENT_BUFFER_SIZE (BUILDING_STATE_DYNAMIC_RESOURCES + 8)

Expand Down
4 changes: 2 additions & 2 deletions src/city/gods.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ static void perform_small_curse(god_type god)
city_message_post(1, MESSAGE_VENUS_IS_UPSET, 0, 0);
city_data.sentiment.blessing_festival_boost -= 15;
city_health_change(-10);
city_sentiment_update();
city_sentiment_update(0);
break;
}
}
Expand Down Expand Up @@ -162,7 +162,7 @@ static int perform_large_curse(god_type god)
city_health_change(-20);
}
city_data.religion.venus_curse_active = 1;
city_sentiment_update();
city_sentiment_update(0);
break;
}
return 1;
Expand Down
Loading