diff --git a/C3X.h b/C3X.h index 66f5af79..54739685 100644 --- a/C3X.h +++ b/C3X.h @@ -73,6 +73,9 @@ struct unit_type_limit { int per_civ; int per_city; int cities_per; + int resource_id; + int per_resource; + int resource_per; }; struct work_area_improvement { diff --git a/default.c3x_config.ini b/default.c3x_config.ini index 42eacf65..7633932c 100644 --- a/default.c3x_config.ini +++ b/default.c3x_config.ini @@ -665,10 +665,10 @@ civ_aliases_by_era = [] leader_aliases_by_era = [] ; Here it's possible to limit how many units of each type players may build. Example: -; ["Royal Guard": 3, Champion: 1 per-city, "Heavy Tank": 3 cities-per, "Heavy Infantry": 5 + 2 per-city] -; The limits may be constant values or vary depending on city counts. In the example above, players will each be limited to 3 Royal Guards. They may +; ["Royal Guard": 3, Champion: 1 per-city, "Heavy Tank": 3 cities-per, "Heavy Infantry": 5 + 2 per-city, Mercenary: 1 per-resource Gold, "ICBM": 2 resource-per Uranium] +; The limits may be constant values or vary depending on city and resource counts. In the example above, players will each be limited to 3 Royal Guards. They may ; build one Champion for each city they own. They may build one Heavy Tank for every 3 cities they own. It is also possible to combine terms with plus -; signs, as for Heavy Infantry. +; signs, as for Heavy Infantry. They can also depend on resources available. ; The unit limits apply to unit production by players, not all forms of unit creation. Specifically, they apply to city production, upgrading, and ; auto-production from wonders. They do not apply to all other ways units may be created including by being captured, enslaved, spawned from a razed ; city, spawned for barbarians, pre-placed in a scenario, spawned for the AI based on difficulty level, etc. diff --git a/injected_code.c b/injected_code.c index 89e17abd..804d05d1 100644 --- a/injected_code.c +++ b/injected_code.c @@ -1276,6 +1276,7 @@ parse_unit_type_limit (char ** p_cursor, struct error_line ** p_unrecognized_lin struct string_slice name; struct unit_type_limit limit = {0}; + struct string_slice resource_name; if (skip_white_space (&cur) && parse_string (&cur, &name) && (name.len < (sizeof out->name)) && @@ -1292,7 +1293,15 @@ parse_unit_type_limit (char ** p_cursor, struct error_line ** p_unrecognized_lin limit.per_city += num; else if (slice_matches_str (&ss, "cities-per")) limit.cities_per += num; - else + else if (slice_matches_str (&ss, "per-resource")) { + if (!parse_string (&cur, &resource_name)) + return RPR_PARSE_ERROR; + limit.per_resource += num; + } else if (slice_matches_str (&ss, "resource-per")) { + if (!parse_string (&cur, &resource_name)) + return RPR_PARSE_ERROR; + limit.resource_per += num; + } else return RPR_PARSE_ERROR; } else limit.per_civ += num; @@ -1300,18 +1309,25 @@ parse_unit_type_limit (char ** p_cursor, struct error_line ** p_unrecognized_lin } while (skip_punctuation (&cur, '+')); int unused; - if (find_unit_type_id_by_name (&name, 0, &unused)) { - memset (out->name, 0, sizeof out->name); - strncpy (out->name, name.str, name.len); - out->limit = limit; - *p_cursor = cur; - return RPR_OK; - } else { + if (!find_unit_type_id_by_name (&name, 0, &unused)) { add_unrecognized_line (p_unrecognized_lines, &name); *p_cursor = cur; return RPR_UNRECOGNIZED; } - + if (limit.per_resource > 0 || limit.resource_per > 0) { + int resource_id; + if (!find_resource_id_by_name (&resource_name, &resource_id)) { + add_unrecognized_line (p_unrecognized_lines, &resource_name); + *p_cursor = cur; + return RPR_UNRECOGNIZED; + } + limit.resource_id = resource_id; + } + memset (out->name, 0, sizeof out->name); + strncpy (out->name, name.str, name.len); + out->limit = limit; + *p_cursor = cur; + return RPR_OK; } else return RPR_PARSE_ERROR; } @@ -8693,9 +8709,16 @@ get_unit_limit (Leader * leader, int unit_type_id, int * out_limit) if ((unit_type_id >= 0) && (unit_type_id < p_bic_data->UnitTypeCount) && stable_look_up (&is->current_config.unit_limits, type->Name, (int *)&lim)) { int city_count = leader->Cities_Count; - int tr = lim->per_civ + lim->per_city * city_count; + char res_count = leader->Available_Resources_Counts[lim->resource_id];//SUPER DUPER DODGY. + //Only picks up local resources, has a habit of being 1 short, unless only 1 resource exists. + //It's weird enough that this logic tracks for so many resources, but I wouldn't be surprised at excessively large coincidences in testing. + int tr = lim->per_civ; + tr += lim->per_city * city_count; if (lim->cities_per != 0) - tr += city_count / lim->cities_per; + tr += res_count / lim->cities_per; + tr += lim->per_resource * res_count; + if (lim->resource_per != 0) + tr += res_count / lim->resource_per; *out_limit = tr; return true; } else